Reputation: 2910
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
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
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