So. What's next in language design?

@yole Is this blog post online?

It is now (finally). https://blog.jetbrains.com/kotlin/2017/06/kotlin-future-features-survey-results/

2 Likes

Let’s talk language features. Type classes, better generics, etc.

A while ago I had a look at Swift. I was surprised how elaborate and feature ridden it is. Some bad suspicion arose inside me and after surfing the Internet for a while it turned out I was right: Swift 2 has problems with long compilation times that are of practical importance. I hope the Kotlin guys will continue to do things the way they used to do them: think about every new feature whether it is needed, whether it can be implemented by extending some already existing feature, whether it can be implemented in the library, and don’t put in things too quickly (all the things that after a while are taken out of Scala again, OMG).

2 Likes

I agree. It is a very bad idea to increase the number of language features uncontrollably. It is very good that some features are implemented not as language constructs, but as global functions, but there are already some disturbing moments. For example property getter and setter notation allows to save a few lines of code, but introduces whole new (and in my opinion unnecessary) language construct to do so.

I’d like to use this opportunity to advocate for macros as a language feature to allow implementation of other language features, in following with Kotlin’s general preference for all things minimal and pragmatic. Some example features that would be naturally implemented as macros:

  • Lenses. The idea of lenses are exceptionally popular among functional language purists. Broadly speaking, you set up a “getter” and “setter” lambda and they can then be composed together to allow you to reach deeply into some data structure, update one value within, and get out a suitable new object without actually mutating the old one. So, let’s say you want to implement lenses for Kotlin. Ideally, you’d have some kind of annotation on a data class which would auto-generate the lens-related code. To show how this might work, here’s a Scala example using the Monacle library. Note how they use the @Lenses macro to do all the work and then they show you the manually-written alternative? The implementation of the macro requires cases to deal with the complexity of Scala.

  • Automatic serialization / deserialization. Say you want to do the same thing, as above, but rather than generating code for lenses, you instead want to generate code for JSON or protocol buffers. You could try to implement this with reflection, but you give up compile-time type safety in your implementation, whereas macro-generated code would then be fed back through the type checker as normal. I haven’t looked closely at the Kotlin Serialization project, but a good macro system would provide the sort of building blocks you’d want to make serialization simpler. Once again, here’s a Scala library that does this with macros, and the macro code reflects the complexity of the source language.

  • Linear type annotations. All the rage with Rust these days is its use of linear types, guaranteeing that there is never more than one live reference to any given object. This can have some remarkable benefits if you’re willing to wrap your head around their intense type system of “owners” and “borrowers”. What if somebody wanted to do something like this in Kotlin? With macros, maybe yes, depending on the degree to which the macro system exposed the type system, you could automatically add type annotations and generate checks to enforce them. This sort of thing could be particularly useful for Kotlin/Native, allowing Kotlin and Rust code to interoperate, since both ride on top of LLVM. So, if a Kotlin/Native user really wants to have a linear-typed subsystem, it would be cool if that could be bolted on without having to disturb the core language.

To some extent, there’s not all that much difference between a macro system and a compiler plugin infrastructure, except the macro system has hopefully better support for managing language syntax and some degree of soundness, such that the macro system won’t easily allow you to generate code that subsequently fails to compile. Without getting lost in a world of lambda calculus and such, I suppose one of the key challenges in supporting any macro system / compiler plug-in infrastructure is what you want to use as your representation. Do you want to define some “core language” and “desugar” Kotlin down to that first?

EDIT: For what it’s worth, Rust’s macro system seems very pretty. Kotlin could do worse than to borrow from it.

2 Likes

Compiler plugins will allow you to do exactly this, at various levels of abstraction. The added benefit is that both the compiler and the IDE will use the same system, which will understand things like incremental compilation.

What I want in a type system:

Check out Ur/Web (The Ur Programming Language Family) for a functional language with type-safe HTML, SQL, etc., compile-time checking of internal links, etc. I imagine a type-safe SQL builder for Kotlin wouldn’t be too hard or too ugly.

It also has an awesome feature that it uses channels for inter-thread communication and you can “cut” your code at any channel to have one half run on the server as native code, and the other on the client as JavaScript :slight_smile: Not totally impossible for Kotlin…

+1 to pattern matching and type classes. This would give Kotlin the potential to completely replace Scala for me

2 Likes

I’m not sure about type classes (at least I don’t want to have implicit conversion in Kotlin), but pattern matching would be really useful. That is the feature from Scala I miss the most in Kotlin.

@medium I agree implicit conversions are difficult to justify given Kotlin’s language design principles, but typeclasses can be implemented in a way that would not require the use of implicits as they are implemented in Scala. We could have multiple implementations of a given typeclass for a given type and the ambiguity being resolved by only one being allowed in scope (and chosen via imports). Under the hood the compiler would use a search of some kind similar to how implicit resolution works, but it wouldn’t be exposed to users as a general feature like in Scala.

Type classes is the very interesting feature. It does not require implicit conversion and could at fact work as groovy traits. It would work the same way marker interface works with the only difference that those marker interfaces could be added to existing classes without inheritance. I think that there is a huge discussion in KEEP so I won’t add any syntax ideas here, but I think that it is possible to make the whole idea work in static without any implicit casts or even reflections.