Require @ for annotations


#1

From http://kotlinlang.org/docs/reference/annotations.html:

"In most cases, the @ sign is optional. It is only required when annotating expressions or local declarations:

```kotlin
fancy class Foo {
  fancy fun baz(fancy foo: Int): Int {
    @fancy fun bar() { ... }
    return (@fancy 1)
  }
}```
"

I propose to require @ in all cases for the following reasons:

  • One way to do it makes for a consistent coding experience (reading + writing both)
  • Making @ optional doesn't offer a big usability and/or readiblity boost (if any at all)
  • It's just one more thing to remember -- extra baggage in the language with little to no benefit

Thank you,

Ehsan


#2

Hi,

I’ve created a pull, for this topic, in kotlin community in G+ and apparently most people are in favor of using @.
have a look here .

Cheers,


#3

Thanks, I voted for Java-style annotations. For me the "convenience" of not having to type @ doesn't justify the cost it incurs (mental baggage + code inconsistenty).


#4

We are actually considering doing this in the near future. Thanks!


#5

Sounds good, thank you.


#6

I'm not super strongly opposed to this idea, but I would argue that many of Kotlin's strengths are in the "more than one way to do it" department. Type-safe builders, for instance, carry an equal (if not greater) amount of mental baggage since they can be used to create rather abstract DSLs compared to more "traditional" approaches. Provided a reader/author is familiar with the language, I rather like seeing them treated like other modifiers, since this fits well with Kotlin's other flexibilities. Overloaded operators and infix notation are two other examples that may carry this "burden", but are useful for cutting down on unnecessary verbosity. Having a `fancy class` feels almost no different to me than having a `private class`... it just has a domain-specific meaning.

That’s just my two cents though. :slight_smile:


#7

How would that interact with the goal of using annotations rather than keywords?

It could end up with Kotlin code having @ symbols scattered around more or less at random, due to what are in effect implementation details. I quite like the current way: it minimizes visual noise most of the time and means things like “data” can be seen as keywords, even though they are not.


#8

My current coding convention is to use `@` for annotations that start with uppercase letters and omit the `@` for annotations that start with lowercase letters.


#9

There are actually two types of annotations: runtime and compile time. I feel that this distinction strongly influences my opinion.

Runtime annotations are simply a mistake. A mistake a language like Kotlin has to deal with in order to be fully interopable with Java. Runtime annotations are nothing more than a way to deal with the shortcommings of a programming language. Modern languages, like Kotlin, show that a concise language with constructs to build typesafe DSLs simply cut the need for runtime annotations. This type of annotations can easily lead to broken class designs where classes only make sense when interpreted by the targetting framework. Take for instance javax.validation, it uses annotations to define property constraints. But those constraints only work when you wank your class through a validator. But it doesn’t prevent you from initiating invalid instances from code.   

Then there are compile time annotations. These are the solid ones because the just lead to code. Code that can be used from any jvm language. It just makes our lives easier without creating broken classes. Of course Kotlin’s “data” class is a perfect example of this. I feel that a more keyword like approach is in order here. This kind of annotations feel more like being part of the language itself.

So maybe a third option would be to clear about this distinction:
Runtime annotations: upper cased with a required @ sign
Compile annotations: lower cased with a optional @ sign


#10

What I'm trying to say here is that the benefit of introducing a new construct, keyword or a particular way of doing things should outweigh its cost (mental baggage, incompatibility etc.). In the case of annotations, I believe it's extra mental baggage w/ little value, if any. That said, I'm not particularly in favor of using the @ symbol; I'm just in favor of using one style consistently -- with @ symbol or without @ symobl; choose one and stick to it (at the language level; not talking about conventions here).


#11

> "Runtime annotations are simply a mistake..." There are many, many services that make sense to be applied at runtime such as validation, transactions, auditing, security etc. It's super useful to just annotate a class and get those services. I'm not sure DSLs or language-keywords would be useful for this. For UML, Deployment Diagrams (https://en.wikipedia.org/wiki/Deployment_diagram) may be used to clarifying assumptions about the runtime environment, among other things. So, no I don't agree w/ your comment that runtime annotations are useless or are there just to compensate for language flexibility. I don't think introducing a keyword for such services would be a good idea. It's much easier to evolve annotations than it is to evovle language keywords.

> “Then there are compile time annotations. These are the solid ones because they just lead to code. Code that can be used from any jvm language.”
I’m not sure what you mean here? The consumption of code b/w JVM languages is at the Byte code level, not source code level. Besides, by definition, compile-time annotations are removed by compilers before code is compiled into byte code.

> "So maybe a third option would be to clear about this distinction:
> Runtime annotations: upper cased with a required @ sign
> Compile annotations: lower cased with a optional @ sign"
If you see my recent comments, you know my take on it. I’m a proponent of consistency so just one way of annotating classes would do fine. Conventions to make certain things upper case (constant values largely) are anyways one of the reminents of Hungarian notation (https://en.wikipedia.org/wiki/Hungarian_notation) that, given our modern IDEs, should really die. Though I do make constant values upper case to be consistent w/ the generally accepted Java convention.


#12
There are many, many services that make sense to be applied at runtime such as validation, transactions, auditing, security etc. It's super useful to just annotate a class and get those services. I'm not sure DSLs or language-keywords would be useful for this. For UML, Deployment Diagrams (https://en.wikipedia.org/wiki/Deployment_diagram) may be used to clarifying assumptions about the runtime environment, among other things. So, no I don't agree w/ your comment that runtime annotations are useless or are there just to compensate for language flexibility. I don't think introducing a keyword for such services would be a good idea

It's a mistake, I'm not calling it useless. Just like e.g. null isn't useless, it's considered by some as being a mistake. Nor am I advocating for more keywords, I don't know where you get that idea from? My point is something like a transaction (just picking one from your list here) can just as easily be achieved by code if a language supports the proper constructs (like Kotlin does). e.g.:

fun someMethod() {   withTransaction {   //do within transaction   } }

This reads clearly, and most importantly, doesn't break. Unlike annotations where you have to rely on proper setup for the method to be proxied and be performed within a transaction. Same goes for validation, security, etc.. Forgetting to properly jam your class through an annotation preprocessor leads to code actually performed without the proper transaction, security measures or validation. Do you understand the problem I'm trying to describe that plain old code doesn't have?

I'm not sure what you mean here? The consumption of code b/w JVM languages is at the Byte code level, not source code level. Besides, by definition, compile-time annotations are removed by compilers before code is compiled into byte code.

That's exactly what I mean. Annotations like `data` differ because it instructs the compiler to emit extra (byte)code. That code is just code and won't behave differently from whatever (jvm) language you use it. It are instructions for the compiler to do some extra work. Those are really helpfull because it makes our lives easier without the chance of being misused of not run with the appropiate accompanied framework.

If you see my recent comments, you know my take on it. I'm a proponent of consistency so just one way of annotating classes would do fine.

Yes I know what your take on it would be, but this is a discussion forum on which I'm offering a different perspective. :) So don't get me wrong here, I'm also a big proponent of consistency. I just think the two types of annotations are simply 2 different things and shouldn't both be considered/called an 'annotation`


#13

Hi there,

I also don’t like inconsitent styles of annotations (I’m currently working with a couple of other Kotlin devs and find myself cleaning up annotation defintions for consistency).

A few other options:

  1. Forbid @ decorations when they aren’t required
  2. Provide a “Remove redundant @ decorations for whole project” option
  3. Or the inverse "Apply @ decorations for whole project"
  4. Require @ decorations but de-emphasise them in the IDE


I’d favour 1 or 4 so all Kotlin projects are consistent.

There’s also the related debate around case conventions for annotations.

I guess I’m also largely in Mark Platvoet’s camp of wishing annotations were deprecated in favour of functions.

Cheers,
Andrew


#14

1. sounds easiest.

The reason for the inconsistency is something technical related to the parser, if I recall correctly. It’s not a stylistic choice. Or rather, the decision is: limitations of parsing one or two rare constructs should not dictate the look of the language everywhere else.