Mark McKenna
Mark McKenna

Reputation: 2910

What are the limits on dynamic/double dispatch in Kotlin?

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<String>) {
    val h: Animal = Horse
    val d: Animal = Donkey
    val child = h + d
}

Based on the above code above, 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!

Upvotes: 3

Views: 2574

Answers (2)

Kirill Rakhman
Kirill Rakhman

Reputation: 43851

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.

Upvotes: 7

D3xter
D3xter

Reputation: 6445

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.

Upvotes: 0

Related Questions