In general I like Kotlin syntax a real lot (mainly the "almost everything is an expression" thing) but there are things that I find surprising/confusing (time ago we saw one of them). Recently, when reading a bit about Ktorm, the object-relation mapper, I came across some rather surprising syntax. The article itself mentions it and explains what's going on (otherwise I don't think I had manages to understand how that was working), but I think it'll be useful to me to put it here.
interface Department : Entity {
companion object : Entity.Factory()
val id: Int
var name: String
var location: String
}
val department = Department()
So the above code seems as if we were somehow creating an instance of an interface (Department), which is obviously not possible. I can think of 2 other situations where we write code that looks similar, but with a different explanation.
One case is the special syntax for functional interfaces/SAM conversions
val runnable = Runnable { println("This runs in a runnable") }
And the other case are object expressions with the object (of the anonymous class) implementing an interface. But the object: syntax, and the "class body" makes clear that we are not "instantiating that interface".
interface Writable {
fun write(): String
}
//object expressions implementing interface, there's not () after the interface name
val o2 = object: Writable {
var name = "Francois"
override fun write() = name
}
The case we're dealing with in this post is a different thing. The original article explains it:
The Entity.Factory class overloads the invoke operator, so we can use brackets to call the companion object as it’s a function. The code creating a department object:
val department = Department()
That’s the charm of Kotlin, Department is an interface, but we can still create its instances, just like calling a constructor function.
What that means is that in the end that code that seemed as if we were invoking a sort of "interface constructor" indeed was calling the invoke method of the companion object of that interface, that is:
val department = Department()
// is right the same as:
val department = Department.Companion.invoke()
No comments:
Post a Comment