This page is no longer maintained — Please continue to the home page at www.scala-lang.org

annotation arguments in scala need to be constant

4 replies
ido
Joined: 2011-05-02,
User offline. Last seen 42 years 45 weeks ago.

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

bmaso
Joined: 2009-10-04,
User offline. Last seen 2 years 40 weeks ago.
Re: annotation arguments in scala need to be constant


On Mon, May 2, 2011 at 6:20 AM, ido <idomtamir@gmail.com> wrote:
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 = "";
 }


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).

 

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



--
Best regards,
Brian Maso
(949) 395-8551
Follow me: @bmaso
brian@blumenfeld-maso.com

ido
Joined: 2011-05-02,
User offline. Last seen 42 years 45 weeks ago.
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

bmaso
Joined: 2009-10-04,
User offline. Last seen 2 years 40 weeks ago.
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:
>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

ido
Joined: 2011-05-02,
User offline. Last seen 42 years 45 weeks ago.
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

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland