Make square brackets mandatory for annotations

jugglingcats wrote:

Agree that making them mandatory would be simplest, but as others do I like the simple syntax like “data class Xyz”.

But I really hate the method confusion for annotations with parameters!

Some more possible options:

  • Change the syntax for parameters, eg: myannotation{name=“food”}
  • Give flexible compiler options with sensible defaults, so teams can choose their preference. Options should include never allow without brackets, always allow, allow only if lib author flagged it, only allow if no parameters

I agree somewhat with Chris Helmbold’s comment though that if a team has to think about it, it’s a problem… so controlling with compiler options not ideal.

Compiler options basically fork the language and this is too bad. If you download some source code, they’ll first have to find out with what options it works and then rewrite it if you want to use it in your project. With more such options, incompatibilities could arise and there may be two files for which no common options exist.

Including these options in the source files would be IMHO better, but I’m not sure if it’s worth it. I could imagine to give a special treatment to a few most common annotions and that’s all. Or do nothing and write

[data] class MyClass
or
#data class MyClass

or whatever. It’s not very nice, but making the whole code look inconsistent just too save a few chars in some places is more ugly.

yep, -1, let the users decide if they use it or not

I think, that would be a good idea, since it would limit useless syntax variance a bit. Maybe it could even be the other way around: force infix notation in certain cases.

I think, that would be a good idea, since it would limit useless syntax variance a bit. Maybe it could even be the other way around: force infix notation in certain cases.

And the next step would be to allow the infix notation to coexist with the nomal call, i.e., to let a to b mean something different from a.to(b). :^O

val map = hashMap(
  "one".to(1),   // <- would anyone prefer this?
  "two" to 2   // <- this looks much clearer, so forbidding the normal syntax for to seems to make sense
)

It would be nice to be able to force infix notation but you need to have the option to use standard notation to support nullable types. e.g.

val foo: Foo? = ... val bar1 = foo?.bar(1) // legal, if foo is null, bar1 is null val bar2 = foo bar 1   // not legal because foo can be null

Unless there's another way to handle null safe invocation of infix functions.

See here for another discussion about infix functions:

http://devnet.jetbrains.com/thread/437602

Whatever is done or not done in regards to brackets and infix notation I very much hope that Kotlin sticks with the philosophy of being simple and side-effect free.  I've always seen Kotlin as "more Java than Java" in that regard.  Scala and Groovy are more complicated languages than Java and have made the decision to go with power over simplicity in many regards.  I think it's best that Kotlin does the opposite and sticks with Simplicity over power.  If that means we can't have DSLs that are as sexy as the ones in Groovy or Scala I think that is a fair trade.

I believe that, since Kotlin is supposed to be used with an IDE (like any modern programming language), there is no point in adding square brackets around when the IDE colors the annotation in a different way

Not all code is viewed inside an IDE. Best counter-example are programming books. I think the slightly nicer syntax isn't worth the confusion.

[foo bar=baz]

This looks nice, but don't forget nested annotations (see JPA for example), although I'm not sure if it would still look good with nested annotations.

I fully agree. There is a big amount of terrible Scala APIs! Scala encourages to write DSL, even though there is no "domain" with the "language" the API promotes. Take a look at these silly method names of SBT: % and %%. Isn't the meaning and the difference obvious?!

APIs should reflect domain knowledge, but I consider DSLs a bad thing in general.

medium ha scritto:

I fully agree. There is a big amount of terrible Scala APIs! Scala encourages to write DSL, even though there is no “domain” with the “language” the API promotes. Take a look at these silly method names of SBT: % and %%. Isn’t the meaning and the difference obvious?!

APIs should reflect domain knowledge, but I consider DSLs a bad thing in general.

I think that there are two problems with Scala

  1. a technical problem. Scala took inspiration from Ruby’s (and Smalltalk’s) operator overloading: that is, operators are just symbolic method names. This made it possible for developers to come up with monstrosities like Scala Graph http://www.scala-graph.org/guides/core-initializing.html
    But then again, the idea of coming up with silly method names is a consequence of them being in the core of the language from the beginning; which people intended as if the authors of the language endorsed the practice; thus…

  2. … there was a cultural problem: the language has been advertised from the beginning to be extremely flexible and silly operators were in the core language, like /: and : for foldRight and foldLeft  Now, the Scala community has grown up, so this is much less of a problem than it was at the beginning; still we have things like :=, %, and %% in sbt, where they might make sense, since it is a DSL for builds; nonetheless, there are much worse things wrong with SBT, according to what I’m reading around; but I digress. Oh, and we still have Scalaz. http://eed3si9n.com/learning-scalaz/Either.html

My point is, silly symbolic names have been part of the Scala ecosystem because people felt like they were endorsed by the authors of the language as the idiomatic way to write code. Now:

  1. Kotlin does not allow to invent arbitrary symbolic method names. Only a bunch of operators can be overloaded, and that is all.
  2. If Kotlin advertises itself from the beginning as an ecosystem where funny-looking method names are not welcome, then it will be the community to reject the misuse of the feature

So, in conclusion, I’m all for a clean language, but do not fear to add controlled power to the language. If we end up with a slightly-better Java 8, then what’s the point of using Kotlin at all? I believe that much of the features of Kotlin are already in Java 8 and some of the sugar can be added with a tiny bit of Project Lombok http://projectlombok.org
If we want Kotlin to gain traction, then it should provide a little bit than that, don’t you think? I believe that Kotlin has already hit that sweet spot between expressive power and cleanliness, now it’s only a matter of squashing bugs and little else.

I for one, love the idea that simple annotations may look like keywords (Ceylon does it too); it makes the code look cleaner, and there’s a great IDE to highlight them the right way. So…

medium ha scritto:

I believe that, since Kotlin is supposed to be used with an IDE (like any modern programming language), there is no point in adding square brackets around when the IDE colors the annotation in a different way

Not all code is viewed inside an IDE. Best counter-example are programming books. I think the slightly nicer syntax isn't worth the confusion.

but is that really a counter example? books can be easily typeset in a different way (with colors and styles); moreover, there might be cases when you do not actually want to let the user know a particular keword is an annotation. Consider the data annotation. Is it an annotation or a keyword? In my view, it may be both; so why distinguish? This is also what Ceylon is doing. Now, I'm not saying that *all* the annotations should be unquoted, otherwise you end up with silliness like http://ceylon-lang.org/documentation/1.0/introduction/#typesafe_metaprogramming_and_annotations I'm just saying that having a nice way to add new keyword-like syntax to the language is pretty sweet and convenient.

For instance, what is the point of telling a first-time user that data is an annotation? An expert user can already tell; a beginner wouldn’t know what they are. But then, why should [data] go between brackets? Why aren’t [public] and [private] within brackets as well?

is that

@foo(bar=@baz(qux=@quux)) [foo(bar=baz(qux=quux))] [ foo bar = [ baz qux = [quux] ] ]

the third syntax is more lispy. Not that being lispy is necessarily a good thing :-)

anyway I don’t really see much improvement in any of them