In the interest of silly thought experiments whose primary purpose is to explore how part of a language works, I decided I wanted to explore a method of making Python programmers more comfortable in Kotlin. Simplistically, I can do this by adding:
class Foo {
private val self:Foo get() = this
...
}
(Aside Question: Is there a more generalized way to refer to Foo
as the return type there so that if I changed Foo
to Bar
, the variable type of self
would still refer to the "implementing class of this method"?)
Having to put that line in each class so that we can feel selfishly pythonic is tedious though. So I turned to an Interface. What I initially wanted is something like Swift's Self
type for Protocols. But I couldn't find anything like that in Kotlin. After reading https://kotlinlang.org/docs/reference/generics.html (which seems to be about Java as much as Kotlin), I concluded that perhaps "Declaration Site Variance" was the thing for me:
interface Selfish<out T> {
val self:T get() = this as T
}
class Foo:Selfish<Foo> {
}
This is better. It's undesirable that I have to list the class name twice in the declaration, but I don't think there's a way around that. Is there?
Additionally, this works for final classes, but if I want to have a class hierarchy that conforms to Selfish at the root level, things fall apart:
class Foo:Selfish<Foo> { ... }
class Bar:Foo { ... }
Methods in Bar that use self
are of the wrong type. And adding , Selfish<Bar>
creates a conflict.
Is there a tool I haven't discovered yet to make the type refer to inherited type?
Is there another approach (other than Interfaces) to do something like this?
Did I make the wrong choice using "Declaration Site Variance"?
I think you should take a look at extensions.
So you can write
fun <T>Foo.getSelf(): T {
return this as T
}
Then if you have
open class Foo
class Bar: Foo()
so
Bar().getSelf<Bar>()
will return object of Bar
class
Or even easier, you can write
fun <T:Foo>T.getSelf(): T {
return this as T
}
so you can call just
Bar().getSelf()
to get instance of any class extended from Foo