Upcoming Change: Syntax For Annotations

Kotlin’s syntax for annotations was inspired by C#, which surrounds them with square brackets:

But brackets are precious for a language designer, and we would really like to use them later for something else, so we are considering changing the annotation syntax to the more Java-like @-based one:

NOTE: the short syntax that does not require [...] nor @ is going to be kept anyways, so you will still be able to say this:

This change has some implications, though.

Labels

First of all, the @-syntax is already in use, for labels:

Since expressions can be annotated as well as declarations, we need to change something here. The simplest option would be to move the @ to the end of a label declaration:

Note that the use site (break@loop) is not changed, and still looks pretty nice :)

Targeting

We are also looking into how we could prescribe what an annotation should be attached to in the generated .class-file:

We have quite a few options here: the @Ann annotation can be put on

  • the field where foo is stored
  • the property foo itself (not a Java declaration)
  • getter of foo
  • setter of foo
  • parameter foo of the primary constructor of C

Some annotations are only applicable to, say, fields, and for those there’s no question, but some allow many possible targets. To express the intent, some additional syntax is needed.

One option would be to prefix the annotation type name with the target(s):

(many targets can be separated by a comma)

Another option would be to do what Scala does:

  • Downside: too many parentheses
  • Upside: @field is also an annotation (yes, Ann is an annotated annotation), which means more extensible syntax and fewer concepts in the language

Yet another option would be to have @field annotation whose arguments are annotations for the field:

  • Upside: even fewer language changes than the previous case
  • Downside: if the same annotation goes to two targets (e.g. getter and setter), it has to be duplicated

A modification of this approach:

Then definitions are as follows:

And, for completeness, yet another approach involves adding an explicit (optional) syntax for declaring fields (inside properties):

  • Downside: There’s no way to mitigate duplication here
  • Downside: It is likely to become an obscure piece of syntax (like $backingField) which is used rarely and supported poorly by tools

Annotations on Local Declarations

Our users seem to often write something like this:

This does not parse correctly, because data is not a keyword (neither is open, btw), so we need to write it like this:

Now, what if I want an open local class, or abstract? Those are modifiers, not annotations, and we can’t say @open or @abstract.

One option is to allow escaping modifiers with @ as well as annotations:

Other options include allowing modifiers on the same line with the class, but this does not straightforwardly extend to functions, which are expressions now. See more here

Feedback Welcome

What do you think?

P.S. BTW, we are working on a spec document draft here

About Andrey Breslav

Andrey is the lead language designer of Kotlin at JetBrains.
This entry was posted in Language design. Bookmark the permalink.

29 Responses to Upcoming Change: Syntax For Annotations

  1. Stephen Colebourne says:

    Using @ instead of [] is definitely cleaner, and clearer to Java developers. The label syntax is OK, but may be worth considering @label@ (surrounded by @).

    The targeting discussion is full of long, complicated syntax options which are mostly high density noise. If people need that much control, then the last option is by far the clearest. This comes back to my last comment, where I find the constructor embedded in the class declaration to be very confusing and dense. Those primary constructor simply have too much information in one spot and will result in very long and confusing declarations. Its also weird now there are actual constructors.

    The “Annotations on Local Declarations” discussion suggests to me that the concepts – annotations, modifiers and keywords – are getting confused. A radical solution would be as follows:

    class(data) Example(val foo: String, val bar: Int)
    class(open) Example(val foo: String, val bar: Int)

    If the declaration part is moved even more options appear:

    class data Example {
    new(val foo: String, val bar: Int)
    }

    Putting it together gives:

    class data Example {
    @Ann1(“arg”)
    val foo: String
    @Ann2
    field _foo
    @GetterAnnotation
    get
    val bar: Int
    new(foo, bar)
    }

    TLDR, Kotlin is outgrowing primary constructors (field declarations embedded in the class declaration). Separate the two concepts, and lots of syntax space appears.

    • Stephen Colebourne says:

      Just to also note that labelled blocks could still use @ with care. This is already allowed:

      ints.forEach @lit {
      … return@lit
      }

      So the for loop label syntax could be

      for @loop (i in 1..20) {
      … break@loop
      }

      And more generally, to label any block, extend use of the do keyword:

      do @mylabel {
      … break@mylabel
      }

      (slightly less flexible than labelling anything, but its a rare edge case anyway)

      Having said all that, using @ at all for jumps is confusing when it does not mean annotation, and calls to use # should be considered.

      • Petr Doležal says:

        I like using @ for annotations (due to the similarity with Java) and I never liked much using it for labels. On the other hand, I understand that many others like break@label syntax and I myself admit it does not look so bad 😉

        So, I like your idea of using labels after keywords like for or do. It seems like a good compromise taking the good from both sides. And speaking for myself, I think it really helps to spot quickly if @something is a label or an annotation.

    • Oliver Plohmann says:

      The label syntax is OK, but may be worth considering @label@
      This seems like a good idea to me. It’s intuitive to grasp and easy to remember.

  2. Salomon BRYS says:

    I think that most annotations are used directly “as keywords” rather than with the bracket syntax, and there’s no reason to believe it will change with the @ syntax.
    Therefore, I believe that the label syntax should not be changed (I find it very understandable) and that we should find another syntax for annotations.
    I would advocate exactly the opposite of your proposal: have the @ before the keyword for labels (as it currently is) and have it after for annotations. It should not even need to be part of the identifier.

    The new annoation syntax could be:

    or

    It would be compatible with multiple annotations:

    As for the annotation specifier, my preference goes to anotating annotations:

    which would allow specifying multiple targets:

  3. I have no opinion on annotations, since I almost never use them, but I am wondering why you don’t just use java’s syntax when it comes to labels?

  4. Steven Gertiser says:

    I think strong similarity to the Java-mode is a win. I acknowledge that there are some people who have an aversion to it, but I have always found it comfortable and easy to read and type. I also that “@” as a symbol for annotation fits. I would welcome the change.

  5. Mohammad Shamsi says:

    If you decided to use Java-like annotation syntax, why do you want to keep the short form (data class Foo) too?
    I would really like to see only one of them not both.

    Regarding labels,
    What about having an annotation to define labels ? e.g. @Label(“label-name”).

    • I don’t follow: why changing the way of escaping annotations should lead to requiring escaping everywhere?

      • Mohammad Shamsi says:

        If I understand the topic correctly, after the proposed changes, in order to annotate a class, field or method, one will have two options:
        1- short form: data class Foo
        2- with @: @Data class Foo

        Then the question would be, when to use short form and when to use the java-like form. And I foresee some developers favoring the first way, some others preferring the second way. Why don’t we just drop one of them and have a single way of annotating?

    • Mykhailo says:

      +1
      Why we need short form for annotations at all? Why not always write
      @data class Foo?

  6. Michael Zehender says:

    To make an informed statement, I’d like to know what you have in mind for the brackets. Could you share that?

    I grew quite fond of the bracket syntax even though I didn’t like it in the beginning. Therefore, unless there’s a very good reason I wouldn’t change it.

    The @ at the end of the label looks uneasy on the eye. Surrounding the label with @ looks better, but ist too much clutter for my taste. If you need to replace the @, a hash would be a nice replacement, I think – at least it has something familiar:


    #loop
    for (i in 1..20) {
    if (enough(i)) break#loop
    println(i)
    }

    Regarding the annotation target I like the prefixed approach best, it is clean and clear without the hassle the other options bring. Yes it is a special purpose implementation, but the readability and clarity is worth it, I think.

  7. Jon Renner says:

    Some thoughts:

    Following Java and use @ for annotations seems like a very sensible idea.
    I’m not sure how I feel about ‘label@’, I think it will be confusing to new users of Kotlin. I saw that ‘#’ was suggested in an above comment. But Andrey said that ‘return#label’ doesn’t read very well. What about ‘label#’ and ‘return@label’ ? (I think #label is not good because it looks like a comment from other languages)

    My main concern is that label@ looks like some strange form of annotation at first glance.

  8. someone says:

    New annotation syntax (@something) and label syntax (something@) look like a puzzle.
    How about use different char for annotation (#, % , …) and revert the label syntax?

    #Inject
    fun setFoo(foo: Foo) { ... }


    @loop
    for (i in 1..20) {
    if (enough(i)) break@loop
    println(i)
    }

  9. Даниил Водопьян says:

    Do you consider to do annotating without specifying the target (field, getter, etc) at all?

    Let me clarify the point. As it is stated in the draft, possible targets are field, get, set, property and parameter. All of those are different parts of a property. And now you are looking for a way to target them separately for some cases of fine tuning.

    But kotlin already has a way to distinguish them, that is ‘full declaration’:
    class Foo(val ab: Int, xy: Int) {
    val xy = xy
    get() = $xy
    }
    With that syntax one can annotate the getter or the parameter easily and clear, without any specifiers.

    To satisfy those cases when such a concrete targeting is widely used by, say, a framework, kotlin needs a way to declarete annotations with ‘build-in’ targeting. It may look like inheritance for annotations:
    /* invalid kotlin syntax */
    annotation class MyAnnotated
    // may be applied to any (??) syntax structure
    annotation class MyAnnotatedGetter: MyAnnotated(), AGetter
    // does what MyAnnotated does, may be applied to getters only

    As @Andrey ones said here (ru): https://www.youtube.com/watch?v=CX_K1r0Vklg
    a programming language should allow an artist to ‘draw’ with big patterns, keeping the ability to draw with pixels when nessessary.

  10. Steven Gertiser says:

    @ for annotations keeps it close to Java and I believe that this closeness is and should remain a differentiating factor of Kotlin vis-à-vis other JVM languages.

    So what to do with labels? One idea was using #. # has a cousin in HTML where it is a destination anchor, and in .css where it serves as a selector. In Kotlin # serves a similar semantic purpose — jump to –, or am stretching the idiom too much? Since css is now part and parcel of Java via JavaFX, I think this would also be not amiss.

  11. Даниил Водопьян says:

    I just got this two following ideas:

    As many reasonable comments above say, in the case that kotlin has a one-symbol annotation escaping (@annotation), it MUST NOT be optional, otherwise it is not clear when one should prefer to omit the escaping.

    So lets have a two-symbol brackets-like escaping, but with a useless symbol ‘\’: \annotation\. This is the oldest escaping symbol ever, and it has no use apart from string literals.

    • Next time you want to call any symbol useless, think twice, then think again :)

      The rule for escaping (any escaping) is: use it only when you can’t do without it. As simple as that.

  12. Dale King says:

    Any update on the status of targetting?

Comments are closed.