I’m a little confused about why an object of a certain type can be set to an object of a different type, as long as the second type inherits from the first

Let’s say I have these classes:

interface Foo { val x:Int } class Foo2 : Foo { override val x = 3 fun Foo2Specific():String { return "hi2" } } class Foo3 : Foo { override val x = 4 fun Foo3Specific():String { return "hi3" } } 

Now if I declare an object x of type Foo.

fun main() { val x:Foo x = Foo2() } 

I think it’s a little weird that I set x to be an instance of Foo2(Foo2 inhereting from Foo). But I can accept it, it just implements the interface’s methods Foo2’s way.

However, I think it’s even weirder that I can call x.Foo2Specific, I mean, x is of type Foo ! How does it know about Foo2Specific ?

I also think it’s weird that I can have a

fun doSomething(x:Foo) { } 

and i can pass doSomething any object that inherits from Foo, but now x can only use methods from Foo itself.

Could someone shed some light on what’s going on here, maybe linking to some further reading about this as well? I’ve searched through the kotlin Docs and haven’t been able to find my answer. (Btw these features seem super useful)

submitted by /u/Acidic_Jew2
[link] [comments]