- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
annotation arguments in scala need to be constant
Mon, 2011-05-02, 14:20
Hi,
I can do this in java (I think):
interface Helper {
String name1 = "name1";
}
public class Something {
@Option(name = "option", usage = "a"+Helper.name1)
private String file = "";
}
but not the equivalient in scala - correct?:
object Helper {
val name1 = "name1"
}
trait Helper2 {
val name1 = "name1"
}
class Something {
@Option(name ="option",usage="a"+Helper.name1)
var file = ""
}
error: annotation argument needs to be a constant
best,
ido
Mon, 2011-05-02, 15:27
#2
Re: annotation arguments in scala need to be constant
>No, you can't do this in Java. The arguments to annotations need to be
>statically calculable. You have a reference to an instance field there (I
>think -- "Helper.name1" is not valid Java, so I'm not sure what you were
>intending with that).
Now I really tested it and it compiles fine (in java).
What I tried is to introduce some refactoring safety by referencing
strings from multiple locations (showing only one usage location)
declared as constants also
in an argument to an annotation.
@interface TestAnnotation {
String concatTest();
}
interface ConcatValue {
String val1 = "firstValue";
String val2 = "secondValue";
}
public class MyTest {
@TestAnnotation(concatTest="the static thing "+ConcatValue.val1+"
or "+ConcatValue.val2)
String elem = "e";
public static void main(String[] args){
System.err.println(new MyTest().elem);
}
}
best,
ido
Mon, 2011-05-02, 21:07
#3
Re: Re: annotation arguments in scala need to be constant
Wow, my Java is indeed getting rusty -- side-effect of using Scala 90% of the time.
In the olden days, we would have to use "static final" modifiers in interface fields IIRC. Not sure if I those field modifiers were necessary, or if they were never necessary and we just used the modifiers to be more precise.
So back to your original question: a val in Scala is not the same as a Java field. The "val" declaration creates a method in the JVM class compiled from the Scala source, as shown here:
> cat Test.scala
object Test {
val greeting = "Hello, World!"
}
> javap -private -c Test
Compiled from "Test.scala"
public final class Test extends java.lang.Object{
public static final java.lang.String greeting();
Code:
0: getstatic #11; //Field Test$.MODULE$:LTest$;
3: invokevirtual #13; //Method Test$.greeting:()Ljava/lang/String;
6: areturn
}
^^^ Note that the Test class only has a static method named "greeting()". And in fact the implementation of that method calls the instance method greeting() on the singleton instance MODULE$ of class Test$. That's how scalac compiles Scala object types to equivalent JVM classes.
>javap -private -c Test$
Compiled from "Test.scala"
public final class Test$ extends java.lang.Object implements scala.ScalaObject{
public static final Test$ MODULE$;
private final java.lang.String greeting;
public static {};
Code:
0: new #9; //class Test$
3: invokespecial #12; //Method "<init>":()V
6: return
public java.lang.String greeting();
Code:
0: aload_0
1: getfield #18; //Field greeting:Ljava/lang/String;
4: areturn
private Test$();
Code:
0: aload_0
1: invokespecial #21; //Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #23; //Field MODULE$:LTest$;
8: aload_0
9: ldc #25; //String Hello, World!
11: putfield #18; //Field greeting:Ljava/lang/String;
14: return
}
On Mon, May 2, 2011 at 7:17 AM, ido <idomtamir@gmail.com> wrote:
--
Best regards,
Brian Maso
(949) 395-8551
Follow me: @bmaso
brian@blumenfeld-maso.com
In the olden days, we would have to use "static final" modifiers in interface fields IIRC. Not sure if I those field modifiers were necessary, or if they were never necessary and we just used the modifiers to be more precise.
So back to your original question: a val in Scala is not the same as a Java field. The "val" declaration creates a method in the JVM class compiled from the Scala source, as shown here:
> cat Test.scala
object Test {
val greeting = "Hello, World!"
}
> javap -private -c Test
Compiled from "Test.scala"
public final class Test extends java.lang.Object{
public static final java.lang.String greeting();
Code:
0: getstatic #11; //Field Test$.MODULE$:LTest$;
3: invokevirtual #13; //Method Test$.greeting:()Ljava/lang/String;
6: areturn
}
^^^ Note that the Test class only has a static method named "greeting()". And in fact the implementation of that method calls the instance method greeting() on the singleton instance MODULE$ of class Test$. That's how scalac compiles Scala object types to equivalent JVM classes.
>javap -private -c Test$
Compiled from "Test.scala"
public final class Test$ extends java.lang.Object implements scala.ScalaObject{
public static final Test$ MODULE$;
private final java.lang.String greeting;
public static {};
Code:
0: new #9; //class Test$
3: invokespecial #12; //Method "<init>":()V
6: return
public java.lang.String greeting();
Code:
0: aload_0
1: getfield #18; //Field greeting:Ljava/lang/String;
4: areturn
private Test$();
Code:
0: aload_0
1: invokespecial #21; //Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #23; //Field MODULE$:LTest$;
8: aload_0
9: ldc #25; //String Hello, World!
11: putfield #18; //Field greeting:Ljava/lang/String;
14: return
}
On Mon, May 2, 2011 at 7:17 AM, ido <idomtamir@gmail.com> wrote:
>No, you can't do this in Java. The arguments to annotations need to be
>statically calculable. You have a reference to an instance field there (I
>think -- "Helper.name1" is not valid Java, so I'm not sure what you were
>intending with that).
Now I really tested it and it compiles fine (in java).
What I tried is to introduce some refactoring safety by referencing
strings from multiple locations (showing only one usage location)
declared as constants also
in an argument to an annotation.
@interface TestAnnotation {
String concatTest();
}
interface ConcatValue {
String val1 = "firstValue";
String val2 = "secondValue";
}
public class MyTest {
@TestAnnotation(concatTest="the static thing "+ConcatValue.val1+"
or "+ConcatValue.val2)
String elem = "e";
public static void main(String[] args){
System.err.println(new MyTest().elem);
}
}
best,
ido
--
Best regards,
Brian Maso
(949) 395-8551
Follow me: @bmaso
brian@blumenfeld-maso.com
Tue, 2011-05-03, 13:07
#4
Re: annotation arguments in scala need to be constant
On May 2, 9:49 pm, Brian Maso
wrote:
> So back to your original question: a val in Scala is not the same as a Java
> field. The "val" declaration creates a method in the JVM class compiled from
> the Scala source, as shown here:
>
> *> cat Test.scala
> object Test {
> val greeting = "Hello, World!"
> }
>
> > javap -private -c Test
>
> Compiled from "Test.scala"
> public final class Test extends java.lang.Object{
> public static final java.lang.String greeting();
> Code:
> 0: getstatic #11; //Field Test$.MODULE$:LTest$;
> 3: invokevirtual #13; //Method Test$.greeting:()Ljava/lang/String;
> 6: areturn
>
> }
I understand now.
I had the wrong impression that the vals/defs in an Object are
"static" like in java, but then you could not have inheritance/
overriding.
Its just that syntactically you call them like in java.
thanks,
ido
On Mon, May 2, 2011 at 6:20 AM, ido <idomtamir@gmail.com> wrote:
No, you can't do this in Java. The arguments to annotations need to be statically calculable. You have a reference to an instance field there (I think -- "Helper.name1" is not valid Java, so I'm not sure what you were intending with that).
--
Best regards,
Brian Maso
(949) 395-8551
Follow me: @bmaso
brian@blumenfeld-maso.com