Scala Annotations – Predefined & User-Defined Annotations
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
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.
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.
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
You give me 15 seconds I promise you best tutorials
Please share your happy experience on Google