For example in Java I could write:
public abstract class Element<S extends Snapshot> { ... }
public abstract class Snapshot<E extends Element> { ... }
And then, somewhere, extend this classes:
public class SnapshotImpl extends Snapshot<ElementImpl> { ... }
public class ElementImpl extends Element<SnapshotImpl> { ... }
But when I tried to implement same class hierarchy in Kotlin:
abstract class Element<S : Snapshot>
abstract class Snapshot<E : Element>
I got following compilation errors:
Error:(6, 28) Kotlin: One type argument expected for class Snapshot<E> defined in model
Error:(6, 25) Kotlin: One type argument expected for class Element<S> defined in model
Is there any way to reproduce same type parameter restrictions in Kotlin?
Kotlin doesn't have raw types, you cannot just drop the type parameters.
One option similar to raw types is to use star projections:
abstract class Element<S : Snapshot<*>> { /* ... */ }
abstract class Snapshot<E : Element<*>> { /* ... */ }
But you won't be able to normally work with the type parameters generic members.
Another option is to introduce mutual constraints like this:
abstract class Element<E : Element<E, S>, S : Snapshot<S, E>>() { /* ... */ }
abstract class Snapshot<S : Snapshot<S, E>, E : Element<E, S>>() { /* ... */ }
With this definition, you can be sure that if you define SomeSnapshot: Snapshot<SomeSnapshot, SomeElement>
, the type SomeElement
is aware of SomeSnapshot
, because it is constrained to be derived from Element<SomeElement, SomeSnapshot>
.
Then the implementation would be:
class SomeElement : Element<SomeElement, SomeSnapshot>() { /* ... */ }
class SomeSnapshot : Snapshot<SomeSnapshot, SomeElement>() { /* ... */ }
I recently came across this issue when designing one of the abstract layers of my app. First of the options in hotkey's answer fails to compile with "This type parameter violates the Finite Bound Restriction" (at least with newer Kotlin 1.2.71). The second one works, but can be optimized a bit. Even thought it is still bloated it makes a difference, especially when you have more type parameters. Here is the code:
abstract class Element<S : Snapshot<*, *>> { /* ... */ }
abstract class Snapshot<E : Element<S>, S : Snapshot<E, S>> { /* ... */ }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With