2
votes

I'm just starting to explore Kotlin, and I'm curious about how far it moves beyond Java's core dynamic binding/dispatch semantics.

Let's say I write code that looks something like this:

    class Animal {
        fun add(x:Animal) = Animal()
    }

    object Horse : Animal
    object Donkey : Animal
    object Mule : Animal

    fun Horse.add(x:Horse) = Horse()
    fun Horse.add(x:Donkey) = Mule()

    fun main(args : Array) {
        val h:Animal = Horse
        val d:Animal = Donkey
        val child = h + d
    }

Based on the above code--what can I expect to happen? Do I get a failure at runtime because Horse doesn't implement add(Animal)? Can it accurately differentiate them in calls of the above nature, where the compile-time type of the values being compared was Animal (at least, as written) but their runtime types were more specific? Does it change anything if we used var instead of val?

Thanks in advance.

EDIT: Modified core code--I see the problem the first responder highlighted, I wasn't thinking straight. Clearly I haven't actually compiled this, I'm still kind of exploring at a conceptual level.

Also, I will give it a shot in the actual compiler, but I'm concerned that there will be situations in which it works and others in which it doesn't based on some criteria that I don't fully understand. I wasn't able to find reference docs on how dynamic dispatch is implemented in Kotlin (not sure about it for Java either, for that matter; I wrote something a few months ago that I thought would work based on JVM docs, but it didn't, and I never had a chance to explore exactly why).

Anyhow thanks again!

2

2 Answers

7
votes

So here's a version of your code that actually compiles:

fun main(vararg args: String) {
    val h:Animal = Horse
    val d:Animal = Donkey
    val child = h + d
    println(child)
}

open class Animal {
    fun plus(x:Animal) = Animal()
}

object Horse : Animal()
object Donkey : Animal()
object Mule : Animal()

fun Horse.plus(x:Horse) = Horse
fun Horse.plus(x:Donkey) = Mule

The result is "Animal@1906bcf8".

As far as I understand, extension methods, i.e. Horse.plus(x:Horse) and Horse.plus(x:Donkey), are statically dispatched. That's because they are basicly compiled to the same byte code as the following Java code:

static Horse plus(Horse $receiver, Horse x) {
    return Horse.INSTANCE;
}

By the way, this is a big difference to default methods in Java 8 which are dynamically dispatched based on the runtime type and can be overriden.

0
votes

This code is not compilable at all, because Animal doesnt have any "+" operators.

If they would allow to use Horse "+" methods on an Animal, then you'd get runtime errors, which kotlin/java/etc. tries to prevent.

Kotlin wont work with the runtime-type to resolve methods and stuff, because there are possibilities to produce runtime errors.

What if another thread changes Animal to a Mule in the meantime, the exact line/time when the other thread changes the Animal is not deterministic, so this could lead up to runtime errors.

Val or var doesnt change anything in this situtation.