Scala Annotations – Predefined & User-Defined Annotations

Free Scala course with real-time projects Start Now!!

In our last tutorial, we study Scala Currying Function and here, we will see Scala Annotations, we will learn about Predefined Annotations in Scala Programming Langauge. Along with this, we will cover Scala User defined annotation and define how annotations affect code generation. At last, we will discuss some Standard Scala Annotations.

So, let’s begin with Scala Annotations.

Scala Annotations - Predefined & User-Defined Annotations

Scala Annotations – Predefined & User-Defined Annotations

Scala Annotations

Scala Annotations let us associate meta-information with definitions. We apply an annotation clause to the first definition or the declaration following it. We can use multiple annotations before a definition or declaration in any order.

Scala annotation is of the form @c or @c(a1,…,an), where c is a constructor for class C, which conforms to the scala.Annotation class.

One such annotation is @deprecated. When we put this before a method, the compiler issues a warning when we use this method. Let’s take an example of Scala Annotations.

Let’s Study Scala Method Overloading with Example

scala> @deprecated
| def sayhello()={"hello"}
<console>:11: warning: @deprecated now takes two arguments; see the scaladoc.
@deprecated
^
sayhello: ()String
scala> print(sayhello())
<console>:13: warning: method sayhello is deprecated
print(sayhello())
^

Hello

This lets us use the method; it returns a warning, but not an error.

We can attach an annotation to a variable, an expression, a method, or any other element. This can be a class, an object, a trait, or anything else. When with a declaration or a definition, it appears in front; when with a type, it appears after. With an expression, it appears after and is separated by a colon. To an entity, we can apply more than one such annotation. Here’s an

example:

For classes: @deprecated(“Use D”, “1.0”) class C { … }

For types: String @local

For variables: @transient @volatile var m: Int

For expressions: (e: @unchecked) match { … }

Let’s Know Reasons to Learn Scala Programming Language

Predefined Annotations in Scala

In this Scala Annotations tutorial, we will talk about four kinds of Scala annotations- Java Platform, Java Beans, Deprecation, and Scala Compiler annotations.

Scala Annotations - Predefined &amp; User-Defined Annotations

Scala Annotations – Predefined & User-Defined Annotations

a. Java Platform Annotations in Scala

We have the following Scala annotations on the Java platform:

  • @transient- This means a field is non-persistent.
  • @volatile- A volatile field is one that can change its value outside the program’s control.
  • @SerialVersionUID(<longlit>)- A serial version identifier is a long constant. This annotation attaches this identifier to a class.
  • @throws(<classlit>)- This mentions the class or one of the superclasses of the class for a certain checked exception.

b. Java Beans Annotations in Scala

Under this, we have two annotations:

  • @scala.beans.BeanProperty- To the class containing the variable to which we apply this, it adds getter and setter methods getX and setX. It does so in the Java bean style. Notice the uppercase for the first letter of the variable after ‘get’/‘set’. It only generates a getter for immutable values.
  • @scala.beans.BooleanBeanProperty- Unlike scala.reflect.BeanProperty, it names the getter method as isX instead of getX.

Read about Scala if-else Statements with Statements

c. Deprecation Annotations in Scala

  • @deprecated(message: <stringlit>, since: <stringlit>)- Like we’ve seen in the previous section, this marks a definition as deprecated. Accessing such a definition only issues a warning. It holds an attribute ‘since’ which denotes from when it is to be considered deprecated.
  • @deprecatedName(name: <symbollit>)- This lets us mark a formal parameter as deprecated.

d. Scala Compiler Annotations in Scala

  • @unchecked- When we apply this annotation to a match expression selector, it suppresses warnings about non-exhaustive pattern matches. For an example, it produces no warnings for the following definition:
def f(x: Option[Int])=(x: @unchecked) match{
case Some(y)=>y
}
  • @uncheckedStable- This definition lets a value appear in a path- this is even if it is volatile. Take a look at the following legal definitions:
type A{type T}
type B
@uncheckedStable val x: A with B
val y: x.T

Let’s Discuss Scala do while Loop with Examples

In this, the type A with B is volatile. So, without Scala annotation, the designator x isn’t a path. Then, x.T is malformed. However, the annotation has no effect on definitions with non-volatile types.

  • @specialized- This tells the compiler to generate specialized definitions for primitive types. Optionally, we can provide a list of primitive types. Check the following code:
trait Function0[@specialized(Unit, Int, Double)T]{
def apply:T
}

The compiler uses the specialized version when the static type for an expression matches a specialized variant of a definition.

Scala User-Defined Annotations

We also have some platform-dependent or application-dependent tools. We use two sub-traits from a Scala. Scala Annotation to indicate how we retain these annotations. Class files hold an annotation class instances for a class that inherits from the trait Scala.ClassfileAnnotation.

For one that inherits from the trait scala.StaticAnnotation, the instances are visible to the Scala type-checker for every compilation unit where we access the annotated symbol. An annotation class may inherit from both of these classes, but if it inherits from neither, its instances are visible only locally within the compilation run analyzing them.

Ensuring the Correctness of Encoding

Some Scala annotations like @tailrec check whether the condition is met. If it isn’t, compilation fails. @tailrec makes sure that a method is tail-recursive. Tail recursion is when a function calls itself at its end/tail. This helps keep memory requirements constant. Let’s take an example.

scala> import scala.annotation.tailrec
import scala.annotation.tailrec
scala> def facto(n:Int):Int={
| @tailrec
| def fact(n:Int,result:Int):Int={
| if(n==1) result else fact(n-1,result*n)
| }
| fact(n,1)
| }
facto: (n: Int)Int
Scala> facto(4)
res1: Int = 24

Here, @tailrec makes sure that facto() is tail-recursive. The following format would raise an error:

scala> def facto(n:Int):Int={
| @tailrec
| def fact(n:Int):Int={
| if(n==1) 1 else n*fact(n-1)
| }
| fact(n)
| }
<console>:15: error: could not optimize @tailrec annotated method fact: it contains a recursive call not in tail position
if(n==1) 1 else n*fact(n-1)
^

Let’s discuss Scala Access Modifiers: Public, Private and Protected Members 

Scala Annotations Affects Code Generation

Remember inline methods from Java? They insert the method body code at the place where a call is made to it. Although this results in a longer bytecode, such code runs faster. @inline makes the compiler inline a method if a heuristic about the size of the generated code is met. But it doesn’t guarantee inlining. Scala Annotations like these affect the generated code.

Some Standard Annotations

Scala has various standard Scala annotations. Here, we discuss some of those.

Standard Annotations

Standard Annotations in Scala

a. scala.deprecated

When a method is deprecated, it means it is removed.

b. scala.transient

A transient field is non-persistent.

c. scala.SerialVersionUID

This denotes the static field SerialVersionUID of a serializable class.

d. scala.volatile

Using this, we can use a mutable state in concurrent programs.

e. scala.serializable

This marks a class as serializable.
Read about Scala Data Types with Examples | Escape Value & Typecasting

f. scala.inline

This means the compiler should try to make the annotated method inline.

g. scala.native

This marks native methods. Such a method is one whose implementation is in another language.

h. scala.throws

This denotes the exceptions a method throws.

i. scala.cloneable

This marks a class as cloneable.

j. scala.remote

This marks a class as remotable.

k. scala.unchecked

This applies to a selector in a match expression.
Let’s discuss Scala Functions in detail

l. scala.reflectBeanProperty

This adds setter and getter methods. When attached to a field, this process follows the JavaBean convention.

So, this was all about Scala Annotations Tutorial. Hope you like our explanation.

Conclusion

Hence, we studied about Scala Annotations, associates meta-information definitions. This means they add extra information to the code. In addition, we discussed predefined and user-defined annotations in Scala. At last, we covered, how to ensure the Correctness of Encoding and define the effect of Scala annotations in code generation.

Hope you understood what we had to say. Furthermo, if you have any query, feel free to ask in the comment box.
Related Topic- Learn About Sets in Scala Collections
For reference

Did you like our efforts? If Yes, please give DataFlair 5 Stars on Google

follow dataflair on YouTube

Leave a Reply

Your email address will not be published. Required fields are marked *