Tell Kotlin that a generic type is an interface - kotlin

Let's say I have a class Foo
class Foo {
val noProblem = "Hakuna Matata"
}
I now want to decorate it with an ID. Kotlin's delegates make this relatively painless:
class IdentifiableFoo(
val id: Int,
foo: Foo,
): Foo by foo
interface Foo {
val noProblem: String
}
class FooImpl: Foo {
override val noProblem = "Hakuna Matata"
}
but let's say I have another class Bar that I also want to decorate, and then another Baz, and then another ...
I could just create a IdentifiableXYZ for each of them, of course.
But what I really want is something akin to
class Identifiable<T> (
val id: Int,
thing: T
): T by thing
That I could just use for all of them.
And yes, there's a very good chance that the language doesn't support something like that, but the error message made me think:
Only classes and interfaces may serve as supertypes
so can I do some where magic or something to tell Kotlin that T is required to be an interface?

It is not possible in Kotlin. Kotlin only allows super type to be either a class or an interface. Type parameter cannot be a super type of some class or interface.
One workaround might be using a base interface for all the interfaces you are using. But not sure it solves your problem.
class IdentifiableFoo<T : BaseFoo>(
val id: Int,
val foo: T,
) : BaseFoo by foo {
fun doSomething(a: T.() -> String) {
println(a.invoke(foo))
}
}
interface Foo0 : BaseFoo {
val noProblem: String
}
interface Foo1 : BaseFoo {
val someProblem: String
}
class FooImpl : Foo0 {
override val noProblem = "Hakuna Matata"
}
class Foo1Impl() : Foo1 {
override val someProblem: String = "Some Problem"
}
interface BaseFoo {}
Usage:
IdentifiableFoo<Foo0>(2, FooImpl()).doSomething {
this.noProblem
} // Prints "Hakuna Matata"
IdentifiableFoo<Foo1>(2, Foo1Impl()).doSomething {
this.someProblem
} // Prints "Some Problem"
Playground link

Related

Cloning object of subclass type in Kotlin

I wanted to be able to define a method to clone an object that is the same type of itself. I define the interface requesting such, but the following does not compile or run.
interface Foo {
fun <T: Foo> copy() : T
}
class Bar(private val v:Int) : Foo {
override fun copy():Bar = Bar(v)
}
main() {
val bar1 = Bar(1)
val bar2 = bar1.copy()
}
If however I write the implementing class in Java, it will compile
class Bar implements Foo {
private int v;
public Bar(int v) {this.v = v;}
public Bar copy() {
return new Bar(v);
}
}
I can rewrite the code like the following that compiles:
interface Foo<out Foo>{
fun copy(): Foo
}
class Bar(private val v:Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
However the following will fail with error: no type arguments expected for fun copy(): Foo
val newF = f.copy()
fun <T: Foo> addFoo(
foo: T,
fooList: List<T>,
): MutableList<T> {
val result: MutableList<T> = arrayListOf()
for (f in fooList) {
val newF = f.copy<T>()
result.add(newF)
}
result.add(foo)
return result
}
Is there a good solution to the problem?
The problem here is that Foo doesn't know the exact type of the implementing class, so has no way to specify that its method returns that same type.
Unfortunately, Kotlin doesn't have self types (see this discussion), as they would handle this situation perfectly.
However, you can get close enough by using what C++ calls the curiously-recurring template pattern. In Kotlin (and Java) you do this by defining Foo with a type parameter explicitly extending itself (including its own type parameter):
interface Foo<T : Foo<T>> {
fun copy(): T
}
Then the implementing class can specify itself as the type argument:
class Bar(private val v: Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
And because T is now the correct type, everything else works out. (In fact, the : Bar is redundant there, because it already knows what the type must be.)
Your addFoo() method will then compile with only a couple of changes: give it the same type parameter <T: Foo<T>>, and remove the (now wrong, but unnecessary) type parameter when calling f.copy(). A quick test suggests it does exactly what you want (creates a list with clones of fooList followed by foo).
Since it's often useful for a superclass or interface to refer to the implementing class, this pattern crops up quite often.
BTW, your code is easier to test if Bar has its own toString() implementation, as you can then simply print the returned list. You could make it a data class, or you could write your own, e.g.:
override fun toString() = "Bar($v)"

Kotlin implement `fun` as `val` (Similar to Scala implementing a `def` as `val`)

In Scala you can define a trait with an undefined def to be implemented in the implementing class. Additionally a def can be implemented as a def or as a val.
trait Foo { def bar: Int }
class Baz(val bar: Int) extends Foo // ok
For Context
val has the same meaning in Scala and Kotlin
fun and def are more or less the same in Scala and Kotlin
trait and interface are more or less the same in Scala and Kotlin.
The advantage here is that some implementations of trait can return a static value for bar that is set when the class initializes, and some implementations can generate the value every time bar is accessed.
Is there similar functionality built into Kotlin?
I already tired implementing a fun as a val and that does not work. I currently have the code below, but it feels like there is more boiler plate here than necessary.
interface Foo {
fun bar(): Int
}
class Baz : Foo {
private val _bar: Int = TODO("Some heavy init function.")
override fun bar(): Int = _bar
}
It can be done with a val property instead of a function. When you define a property with just = and no get(), the initialization code is called a single time and assigned to the backing variable, so when the property is accessed, it simply reads the value stored in the backing variable without computing it again:
interface Foo {
val bar: Int
}
class Baz : Foo {
override val bar: Int = TODO("Some heavy init function.")
}
And the interface gives you the flexibility to make it something that is computed on demand (possibly different each time accessed) using a custom getter:
class Baz : Foo {
override val bar: Int get() = Random.nextInt(10)
}
Or computed lazily using a property delegate (the first time it is accessed instead of at class instantiation time):
class Baz : Foo {
override val bar: Int by lazy { TODO("Some heavy init function.") }
}
Or you can upgrade it to be a var and allow external classes to overwrite what is set in the property:
class Baz : Foo {
override var bar: Int = 5
}
Or only internal to the class:
class Baz : Foo {
override var bar: Int = 5
private set
}
With the custom getter, you could do something more complicated involving backing properties, similar to your code with the fun. Or you can design your own property delegate if there's a pattern you use repeatedly.

Type inference of class type parameter in abstract method

// Bars.kt
abstract class Bar
class BarToo(/* fields */) : Bar()
// Foos.kt
abstract class Foo<T : Bar> {
abstract fun foo(bar: T)
}
class FooToo : Foo<BarToo>() {
override fun foo(bar: BarToo) { /* */ }
}
// FoosBars.kt
private val foos = HashMap<String, Foo<out Bar>>()
fun <T : Foo<out Bar>> putFoo(name: String, foo: T) {
foos.putIfAbsent(name, foo)
}
fun doFoo(name: String, bar: Bar) {
val foo = foos[name] ?: return
// Error: Type mismatch: inferred type is Bar but Nothing was expected
// https://pl.kotl.in/TSp3eO_Tj
foo.foo(bar)
}
If I manually specify the bounds of T at the method's declaration, the error in doFoo is resolved, e.g.:
abstract class Foo /* ... */ {
abstract <T : Bar> fun foo(bar: T)
}
but obviously prevents the subclasses from using the type parameter from the class declaration.
Is this type of hierarchy possible in Kotlin, or should I better explain what I am trying to accomplish in order to avoid an XY problem?
Thanks!
You need to use in instead of out. This allows child classes to be used as follows:
foo.foo(bar)
foo.foo(BarToo()) // no compile error
Ref: this

Why do I have to cast in this Kotlin code?

interface Foo<T: Bar> {
fun example(bar: T)
}
interface Bar
class Bar1 : Bar
class Bar2 : Bar
class FooEx1 : Foo<Bar1> {
override fun example(bar: Bar1) { }
}
class FooEx2 : Foo<Bar2> {
override fun example(bar: Bar2) { }
}
// Won't compile
// Even though FooEx1 and FooEx2 *are* Foo<Bar>
class ExampleDoesntCompile {
val collection = mutableListOf<Foo<Bar>>().apply {
this.add(FooEx1())
this.add(FooEx2())
}
}
// Will compile
// But have to cast FooEx1 and FooEx2 to Foo<Bar>
class ExampleDoesCompileButRequiresCast {
val collection = mutableListOf<Foo<Bar>>().apply {
this.add(FooEx1() as Foo<Bar>)
this.add(FooEx2() as Foo<Bar>)
}
}
So, I could for instance, state that Foo's parameterized type is out, but then I get a compile error for the function example:
interface Foo<out T: Bar> {
fun example(bar: T)
}
Error: Type parameter T is declared as 'out' but occurs in 'in' position in type T
Because generic types in Java / Kotlin are invariant by default. variance
interface Foo<out T: Bar>
If you can't make it covariant, then make the list items covariant
val collection = mutableListOf<Foo<out Bar>>().apply {
this.add(FooEx1())
this.add(FooEx2())
}
//or val collection = mutableListOf(FooEx1(), FooEx2())
So it'll crash at run time with the cast?
Here is example code that would crash:
val foo: Foo<Bar> = collection[0]
foo.example(Bar2())
So if you could create collection without a cast as in your ExampleDoesntCompile, you'd get code without any casts which throws a ClassCastExcepion.
This also shows why the interface can't be declared with out:
val foo: Foo<Bar> = FooEx1() // out would make this legal
foo.example(Bar2())
It would make sense to declare your interface with in, but this would mean a Foo<Bar> is a Foo<Bar1> and a Foo<Bar2>, not vice versa, so still wouldn't let you put FooEx1/2 into a collection of Foo<Bar>s.

How to specify "own type" as return type in Kotlin

Is there a way to specify the return type of a function to be the type of the called object?
e.g.
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
In effect, this would be roughly equivalent to instancetype in Objective-C or Self in Swift.
There's no language feature supporting this, but you can always use recursive generics (which is the pattern many libraries use):
// Define a recursive generic parameter Me
trait Foo<Me: Foo<Me>> {
fun bar(): Me {
// Here we have to cast, because the compiler does not know that Me is the same as this class
return this as Me
}
}
// In subclasses, pass itself to the superclass as an argument:
class FooClassA : Foo<FooClassA> {
fun a() {}
}
class FooClassB : Foo<FooClassB> {
fun b() {}
}
You can return something's own type with extension functions.
interface ExampleInterface
// Everything that implements ExampleInterface will have this method.
fun <T : ExampleInterface> T.doSomething(): T {
return this
}
class ClassA : ExampleInterface {
fun classASpecificMethod() {}
}
class ClassB : ExampleInterface {
fun classBSpecificMethod() {}
}
fun example() {
// doSomething() returns ClassA!
ClassA().doSomething().classASpecificMethod()
// doSomething() returns ClassB!
ClassB().doSomething().classBSpecificMethod()
}
You can use an extension method to achieve the "returns same type" effect. Here's a quick example that shows a base type with multiple type parameters and an extension method that takes a function which operates on an instance of said type:
public abstract class BuilderBase<A, B> {}
public fun <B : BuilderBase<*, *>> B.doIt(): B {
// Do something
return this
}
public class MyBuilder : BuilderBase<Int,String>() {}
public fun demo() {
val b : MyBuilder = MyBuilder().doIt()
}
Since extension methods are resolved statically (at least as of M12), you may need to have the extension delegate the actual implementation to its this should you need type-specific behaviors.
Recursive Type Bound
The pattern you have shown in the question is known as recursive type bound in the JVM world. A recursive type is one that includes a function that uses that type itself as a type for its parameter or its return value. In your example, you are using the same type for the return value by saying return this.
Example
Let's understand this with a simple and real example. We'll replace trait from your example with interface because trait is now deprecated in Kotlin. In this example, the interface VitaminSource returns different implementations of the sources of different vitamins.
In the following interface, you can see that its type parameter has itself as an upper bound. This is why it's known as recursive type bound:
VitaminSource.kt
interface VitaminSource<T: VitaminSource<T>> {
fun getSource(): T {
#Suppress("UNCHECKED_CAST")
return this as T
}
}
We suppress the UNCHECKED_CAST warning because the compiler can't possibly know whether we passed the same class name as a type argument.
Then we extend the interface with concrete implementations:
Carrot.kt
class Carrot : VitaminSource<Carrot> {
fun getVitaminA() = println("Vitamin A")
}
Banana.kt
class Banana : VitaminSource<Banana> {
fun getVitaminB() = println("Vitamin B")
}
While extending the classes, you must make sure to pass the same class to the interface otherwise you'll get ClassCastException at runtime:
class Banana : VitaminSource<Banana> // OK
class Banana : VitaminSource<Carrot> // No compiler error but exception at runtime
Test.kt
fun main() {
val carrot = Carrot().getSource()
carrot.getVitaminA()
val banana = Banana().getSource()
banana.getVitaminB()
}
That's it! Hope that helps.
Depending on the exact use case, scope functions can be a good alternative. For the builder pattern apply seems to be most useful because the context object is this and the result of the scope function is this as well.
Consider this example for a builder of List with a specialized builder subclass:
open class ListBuilder<E> {
// Return type does not matter, could also use Unit and not return anything
// But might be good to avoid that to not force users to use scope functions
fun add(element: E): ListBuilder<E> {
...
return this
}
fun buildList(): List<E> {
...
}
}
class EnhancedListBuilder<E>: ListBuilder<E>() {
fun addTwice(element: E): EnhancedListBuilder<E> {
addNTimes(element, 2)
return this
}
fun addNTimes(element: E, times: Int): EnhancedListBuilder<E> {
repeat(times) {
add(element)
}
return this
}
}
// Usage of builder:
val list = EnhancedListBuilder<String>().apply {
add("a") // Note: This would return only ListBuilder
addTwice("b")
addNTimes("c", 3)
}.buildList()
However, this only works if all methods have this as result. If one of the methods actually creates a new instance, then that instance would be discarded.
This is based on this answer to a similar question.
You can do it also via extension functions.
class Foo
fun <T: Foo>T.someFun(): T {
return this
}
Foo().someFun().someFun()