Annotations vs keywords?

Kotlin uses annotations in a few places I would have expected keywords. For example "synchronized", "platformStatic" and "data" are all annotations. On the other hand "override", "public" etc are keywords. This seems without much rhyme or reason.

For things which are a part of the language and which affect the behaviour of the compiler (like “data”) it feels like a keyword would be superior. For example, annotations don’t flag any error if put in the wrong location. They sometimes need surrounding square brackets for obscure reasons. They clutter up the imports list. Aesthetically, having some keyword-like-things appear in bold and others in green just looks odd.

There may be a good reason why some of these things are annotations and others aren’t. If so an explanation would be interesting.

First of all, "synchronized", "volatile" etc are not part of the language, but rather hints to the back-end that facilitate interoperability with a platform.

Then, the fact that annotation targets are not checked by the compiler, and thus nobody controls where you can apply an annotation is a temporary lack of a definitely needed feature. For some annotations, like “inline”, some of these checks are in place already, for others they will come later.

Your reasoning is correct where it comes to “data”. In fact, those soft keyword that we internally call “modifiers”: “public”, “override” etc. could and probably will be turned into annotations as well, at least internally (the highlighting will likely remain as it is). The argument about square brackets falls into two categories: local declarations will always require square brackets around annotations, and the do not admit modifiers at all; all other contexts will eventually admit annotations without square brackets (when we fix a few parser bugs in this area).

Important note: all modifiers are soft keywords, i.e. you can name a variable “public”, it is not prohibited. In this sense these words are not reserved or anything, so they are very close to annotations indeed.

Bottom-line: you are right in that the division into annotations and modifiers is arbitrary. We will solve this by turning modifiers into annotations. The syntax will be fixed and the checks will be put into their place.

Why we prefer annotations:

  1. This is more flexible and easier to evolve: we might want to add a parameter to some annotation later on, this would not be possible with a modifier.
  2. Theoretically, annotations can be marked deprecated and retired over time. It’s a lot harder with modifiers.
  3. This is more uniform with user-defined things: if you want to write your own annotation-based framework or even a compiler plugin, the syntax will not look “second-class”.
  4. Annotations, being part of the library, require less work to integrate into the language, tooling, docs etc. There’s a uniform way of treating them, and again, it’s not different for user-defined things.

Good answer, thanks.

Do you have any concrete plans for a pluggable compiler, or is this a post 1.0 feature? I’ve thought that an adaption of the Checker framework would be superb. The Kotlin type system is good, but many of the capabilities in Checker always sounded great to me e.g. being able to type ints as seconds vs milliseconds or more flexible immutability typing. If you integrated a version of Checker then you’d potentially get a lot of useful type system enhancements for free without breaking java interop.

We haven't looked into the Checker Framework integration in particular. Altogether, plugin infrastructure is not a priority for 1.0, although we may ship some of it in 1.0