Kotlin
A concise multiplatform language developed by JetBrains
Upcoming Change: Syntax For Annotations
Kotlin’s syntax for annotations was inspired by C#, which surrounds them with square brackets:
[Inject] fun setFoo(foo: Foo) { ... }
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:
@Inject fun setFoo(foo: Foo) { ... }
NOTE: the short syntax that does not require [...]
nor @
is going to be kept anyways, so you will still be able to say this:
data class Foo volatile var bar: Bar = ...
This change has some implications, though.
Labels
First of all, the @
-syntax is already in use, for labels:
@loop for (i in 1..20) { if (enough(i)) break@loop println(i) }
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:
loop@ for (i in 1..20) { if (enough(i)) break@loop println(i) }
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:
class C(@Ann("arg") var foo: Int)
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 ofC
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):
class C(@field:Ann("arg") var foo: Int)
(many targets can be separated by a comma)
Another option would be to do what Scala does:
class C(@(Ann@field)("arg") var foo: Int)
- 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:
class C(@field(@Ann("arg")) var foo: Int)
- 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:
class C(@at(FIELD, @Ann1("arg"), @Ann2) var foo: Int) class C(@atMany(array(FIELD, PROPERTY), @Ann1("arg"), @Ann2) var foo: Int)
Then definitions are as follows:
annotation class at(val target: AnnotationTarget, vararg val annotations: Annotation) annotation class atMany(val target: Array<AnnotationTarget>, vararg val annotations: Annotation)
And, for completeness, yet another approach involves adding an explicit (optional) syntax for declaring fields (inside properties):
@Ann1("arg") @Ann2 val foo: Int = 1 @Ann1("arg") @Ann2 field _foo @GetterAnnotation get
- 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:
fun example() { data class Example(val foo: String, val bar: Int) // Error on this line ... }
This does not parse correctly, because data
is not a keyword (neither is open
, btw), so we need to write it like this:
fun example() { @data class Example(val foo: String, val bar: Int) // OK ... }
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:
fun example() { @open class Example(val foo: String, val bar: Int) ... }
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