From the REPL:
scala> final val x = "x"
x: java.lang.String("x") = x
scala> @javax.persistence.Table(name = x) case class foo()
defined class foo
scala> final val x:java.lang.String = "x"
x: java.lang.String = x
scala> @javax.persistence.Table(name = x) case class foo()
<console>:6: error: annotation argument needs to be a constant; found: x
@javax.persistence.Table(name = x) case class foo()
Can someone explain why this only works without a type?
Without the type, final val
acts like a literal constant -- the identifier is replaced by its value at compile time. With the type, it becomes a reference to something stored somewhere, which cannot be used on annotations.
This is defined on section 4.1 of the specification:
A constant value definition is of the form
final val x = e
where e is a constant expression (§6.24). The final modifier must be present and no type annotation may be given. References to the constant value x are themselves treated as constant expressions; in the generated code they are replaced by the definition's right-hand side e.
This is the only way you can get true named constants in Scala. They have performance benefits, they are really guaranteed not to mutate (even a final val
with a type can be changed through reflection) and, of course, they can be used in annotations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With