alt

In the previous posting we talked about describing a machine in software. What does that mean?

It actually means two things: one is to be able to write down the description of a machine, and the other one is two have a data structure that is equivalent to that description.

That is, we need some syntax, and it needs to be parsed into a data structure.

One of Kotlin’s superpowers is its ability to create Domain Specific Languages (DSLs); that is, Kotlin allows you to create a specific syntax to do something specific to a domain of knowledge; in this case the domain of machines, parts, assemblies, etc.

You may have seen Philip Wadler’s youtube talk on the subject 1, but if you haven’t, GTFO and watch it. Why would you read this instead of listening to him?

Kotlin’s approach is different. In Wadler’s talk, the compiler exposes the guts of the program and let’s you manipulate them; Kotlin’s approach is to let you bend the language to create DSL’s that the compiler can understand and compile.

What I mean is, e.g.:

val machine = product("Car") {
    part("Wheel") {
        qty = 4
        cost = 300*Dollars
    }
    part("Doors") {
        qty = 2
        cost = 1500*Dollars
    }
}

You get the idea: The above is actually a valid Kotlin program, provided you define functions called product(), assembly() and part(). The devil is in the details, I suppose.

The syntax (the Kotlin syntax, that is) might be a bit unclear, if you have not seen it before, but it is one of those simple details that make Kotlin so powerful and fun. Let’s take a first look at, a function called productLike() so that we can begin to see the forest for the trees.

We had already looked at higher order functions /posts/006-function-divertimento/, so look there if the room starts spinning.

fun productLike(init: () -> Unit){}

The above, as we already know, is a function that takes a parameter called block. The type of that parameter is: a function that returns nothing (Unit).

Suppose we also had

fun foo(){}

which is of the type () -> Unit. Because it is of the same type, we can pass foo() as a parameter to productLike().

productLike(::foo)

Kotlin though, supports closures a.k.a anonymous functions. E.g.

val bar = {}

And in this case bar also has the type () -> Unit, and we can pass it to productLike():

productLike(bar)

(the :: in front of foo is to make the distinction between variables and functions).

Like any variable, bar can be inlined, so that last invocation of productLike() is equivalent to:

productLike({})

We are getting close!!

This is the small but simple moment of syntactic elegance that has a tremendous impact overall: iff the last parameter to a function is a closure, the closure can be placed outside the parentheses, so we end up with:

productLike() {

}

And Kotlin further let’s you omit the parentheses if there is nothing inside them.

productLike {

}

So presto, concise, elegant syntax for a function that takes a closure. It is the trick that makes, for instance, using map() in Kotlin so clean:

val someList = listOf("a", "c")
.map { s ->
    s.uppercase()
}
require(someList == listOf("A", "C"))

map() above applies its closure parameter to each element of the list it is dotted with.

In most languages, this implies that map is a method in a class somewhere in the implementation or inheritance of List<T>, but that is not necessarily true in Kotlin. We’ll see next how that vodoo happens.


  1. You should really know who Wadler is, if you don’t already. ↩︎