How to implements circular interface generics in Kotlin [duplicate] - kotlin

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>> { /* ... */ }

Related

How to call an abstract method from a Class parameter in Kotlin?

Aim
Have a function Book, which takes one of three Letter classes as argument myClass and then calls 'genericMethod()' from the abstract class which Letter*() has inherited.
Issue
If I try Book(LetterA()).read() I get the following error:
Type mismatch. Required: Class<SampleClassArguments.Alphabet> Found: SampleClassArguments.LetterA
Does Kotlin have any way to achieve this result?
Code
#Test
fun readBookTest() {
Book(LetterA()).read() /*<--error here*/
}
class Book(val myClass: Class<Alphabet>) {
fun read() {
val letterClass = myClass.getConstructor().newInstance()
letterClass.genericMethod(myClass.name)
}
}
class LetterA(): Alphabet()
class LetterB(): Alphabet()
class LetterC(): Alphabet()
abstract class Alphabet {
fun genericMethod(className: String) {
println("The class is: $className")
}
}
You need to define the Class type as covariant with the out keyword so any of the child classes is an acceptable argument:
class Book(val myClass: Class<out Alphabet>)
And when you use it, you need to pass the actual Class, not an instance of the class. You can get the Class by calling ::class.java on the name of the class:
#Test
fun readBookTest() {
Book(LetterA::class.java).read()
}

Dart : Why should overriding method's parameter be "wider" than parent's one? (probably topic about Contravariant) Part2

https://dart.dev/guides/language/language-tour#extending-a-class
Argument types must be the same type as (or a supertype of) the
overridden method’s argument types. In the preceding example, the
contrast setter of SmartTelevision changes the argument type from int
to a supertype, num.
I was looking at the above explanation and wondering why the arguments of subtype member methods need to be defined more "widely"(generally) than the original class's one.
https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Function_types
class AnimalShelter {
Animal getAnimalForAdoption() {
// ...
}
void putAnimal(Animal animal) {
//...
}
}
class CatShelter extends AnimalShelter {
//↓ Definitions that are desirable in the commentary
void putAnimal(Object animal) {
// ...
}
//↓Definitions that are not desirable in the commentary
void putAnimal(Cat animal) {
// ...
}
//I can't understand why this definition is risky.
//What specific problems can occur?
}
I think this wikipedia sample code is very easy to understand, so what kind of specific problem (fault) can occur if the argument of the member method of the subtype is defined as a more "narrower"(specific) type?
Even if it is explained in natural language, it will be abstract after all, so it would be very helpful if you could give me a complete working code and an explanation using it.
Let's consider an example where you have a class hierarchy:
Animal
/ \
Mammal Reptile
/ \
Dog Cat
with superclasses (wider types) above subclasses (narrower types).
Now suppose you have classes:
class Base {
void takeObject(Mammal mammal) {
// ...
}
Mammal returnObject() {
// ...
}
}
class Derived extends Base {
// ...
}
The public members of a class specify an interface: a contract to the callers. In this case, the Base class advertises a takeObject method that accepts any Mammal argument. Every instance of a Base class thus is expected to conform to this interface.
Following the Liskov substitution principle, because Derived extends Base, a Derived instance is a Base, and therefore it too must conform to that same Base class interface: its takeObject method also must accept any Mammal argument.
If Derived overrode takeObject to accept only Dog arguments:
class Derived extends Base {
#override
void takeObject(Dog mammal) { // ERROR
// ...
}
}
that would violate the contract from the Base class's interface. Derived's override of takeObject could be invoked with a Cat argument, which should be allowed according to the interface declared by Base. Since this is unsafe, Dart's static type system normally prevents you from doing that. (An exception is if you add the covariant keyword to disable type-safety and indicate that you personally guarantee that Derived.takeObject will never be called with any Mammals that aren't Dogs. If that claim is wrong, you will end up with a runtime error.)
Note that it'd be okay if Derived overrode takeObject to accept an Animal argument instead:
class Derived extends Base {
#override
void takeObject(Animal mammal) { // OK
// ...
}
}
because that would still conform to the contract of Base.takeObject: it's safe to call Derived.takeObject with any Mammal since all Mammals are also Animals.
Note that the behavior for return values is the opposite: it's okay for an overridden method to return a narrower type, but returning a wider type would violate the contract of the Base interface. For example:
class Derived extends Base {
#override
Dog returnObject() { // OK, a `Dog` is a `Mammal`, as required by `Base`
// ...
}
}
but:
class Derived extends Base {
#override
Animal returnObject() { // ERROR: Could return a `Reptile`, which is not a `Mammal`
// ...
}
}
void main(){
Animal a1 = Animal();
Cat c1 = Cat();
Dog d1 = Dog();
AnimalCage ac1 = AnimalCage();
CatCage cc1 = CatCage();
AnimalCage ac2 = CatCage();
ac2.setAnimal(d1);
//cc1.setAnimal(d1);
}
class AnimalCage{
Animal? _animal;
void setAnimal(Animal animal){
print('animals setter');
_animal = animal;
}
}
class CatCage extends AnimalCage{
Cat? _cat;
#override
void setAnimal(covariant Cat animal){
print('cats setter');
_cat = animal;
/*
if(animal is Cat){
_cat = animal;
}else{
print('$animal is not Cat!');
}
*/
}
}
class Animal {}
class Cat extends Animal{}
class Dog extends Animal{}
Unhandled Exception: type 'Dog' is not a subtype of type 'Cat' of 'animal'
In the above code, even if the setAnimal method receives a Dog instance, a compile error does not occur and a runtime error occurs, so making the parameter the same type as the superclass's one and checking the type inside the method is necessary.

Sealed classes generics

I have this scenario where I have a super abstract class that emits different types of events using Kotlin sealed classes.
These events are modeled as follows.
sealed class BaseEvent {
object ConnectionStarted : BaseEvent()
object ConnectionStopped : BaseEvent()
}
sealed class LegacyEvent : BaseEvent() {
object TextChanged : LegacyEvent()
object TextCleared : LegacyEvent()
}
sealed class AdvancedEvent : BaseEvent() {
object ButtonClick : AdvancedEvent()
object ButtonLongClick : AdvancedEvent()
}
And here are the classes that emit these events
abstract class BaseViewModel<E : BaseEvent> {
private fun startConnection() {
emit(BaseEvent.ConnectionStarted) // <-- Error
}
fun emit(event: E){
//...
}
}
class LegacyBaskan : BaseViewModel<LegacyEvent>() {
fun textChanged() {
emit(LegacyEvent.TextChanged) // <-- Works
}
}
class AdvancedBaskan : BaseViewModel<AdvancedEvent>() {
fun buttonClicked() {
emit(AdvancedEvent.ButtonClick) // <-- Works
}
}
Here, it only works for the subclass and I can emit any event in the LegacyEvent or AdvancedEvent in their associated classes. However, for the BaseBaskan class, I can't emit the events from the BaseEvent although I stated that the generic type E must extend the BaseEvent.
I need each subclass to have access to its own events as well as the superclass events, but not the other subclasses' events.
How can I still emit events from BaseEvent in the base class, while giving each class the access to emit its own events only?
Not sure if you're confused about why it's not letting you emit the item from the base class. Since E could be any subtype of BaseEvent, if your class could emit ConnectionStarted, then it would be violating its contract any time it is declared as a BaseViewModel<AnythingBesidesConnectionStarted>.
Only way I can think of to make this work is have both private and public versions of the emit function. You might have to change code elsewhere in your class that you haven't shown. If there's some function that returns E, you will have to change it so it returns BaseEvent.
abstract class BaseViewModel<E : BaseEvent> {
private fun startConnection() {
emitInternal(BaseEvent.ConnectionStarted)
}
private fun emitInternal(event: BaseEvent) {
//...
}
fun emit(event: E){
emitInternal(event)
}
}
You can't emit BaseEvent.ConnectionStarted in BaseViewModel (and other events as well) because E is not defined yet, so the type system can't be sure that you won't emit events of another subtype breaking generic type invariance.
Just add an overloaded private version, which accepts BaseEvent argument (you'll need some #JvmName annotation to make it compilable for JVM target):
abstract class BaseViewModel<E : BaseEvent> {
private fun startConnection() {
emit(BaseEvent.ConnectionStarted)
}
#JvmName("emitBaseEvent")
private fun emit(event: BaseEvent) {
//...
}
fun emit(event: E) {
emit(event as BaseEvent)
}
}
It looks like you need contravariance, which can be achieved using in. Assuming your base class only has methods such as emit that use type E as parameter type, not as return type, then:
abstract class BaseViewModel<in E : BaseEvent> {
See https://kotlinlang.org/docs/generics.html#use-site-variance-type-projections.

Out-projected type ... prohibits the use of 'public open fun .... defined in FooTable

I have the following class:
abstract class FooTable<M, D> where M : IModel, D : IDto {
///...
fun getTableData(models: ArrayList<M>): ArrayList<D> {
// ...
}
}
And I have another class using it like:
abstract class FooPage<M, F> where M : IModel, F : IFilter {
abstract val table: FooTable<M, out IDto>
Then somewhere in my code I'm trying to do:
page.table.getTableData(arrayListOf(m1, m2)).first()
And it is giving me:
Out-projected type FooTable<out IModel, out IDto> prohibits the use of public final fun getTableData(models: kotlin.collections.ArrayList<M> /* = java.util.ArrayList<M> */): kotlin.collections.ArrayList<D> /* = java.util.ArrayList<D> */ defined in com.menighin.example.models.FooTable
Here is a fiddle with the problem: https://pl.kotl.in/ryirJJH9m
The code is:
interface IModel
interface IDto
interface IFilter
class Model : IModel
class Dto : IDto
class Filter : IFilter
class FooTable<M, D> where M : IModel, D : IDto {
fun getTableData(models: List<M>): ArrayList<D> {
return ArrayList()
}
fun testPage(masterModel: IModel, thisPage: FooPage<out IModel, out IFilter>) {
thisPage.table.getTableData(arrayListOf(masterModel)) // Error here
}
fun testTable(masterModel: IModel, masterTable: FooTable<out IModel, out IDto>) {
masterTable.getTableData(arrayListOf(masterModel)) // And error here
}
}
class FooPage<M, F> where M : IModel, F : IFilter {
val table: FooTable<M, out IDto> = FooTable()
}
fun main() {
val page = FooPage<Model, Filter>()
val a = page.table.getTableData(arrayListOf())
println("Hello, world!!!")
}
Basically there is a function in my FooTable in which I need to get reference for another Table and get its data. I guess I could pass in the data already but I'm curiou why this isn't working now...
I understand from this question that if I could change abstract val table: FooTable<M, out IDto> to abstract val table: FooTable<M, Any> it would be ok... But, as far as I know, I can't because the definition of FooTable is strict about the second parameter implementing IDto.
How can I fix this?
The problem is that in your testTable function you specify that masterTable's first generic type restriction (IModel) is out. If you change the declaration to this it compiles:
fun testTable(masterModel: IModel, masterTable: FooTable<in IModel, out IDto>)
(Alternatively, specify neither in nor out.)
This is explained here (though does take a bit getting your head round). I think that your existing code (with the IModel generic type restriction of out) states that the masterTable argument produces IModels, but there's no rules about what it takes in. Therefore the error (at least in IntelliJ) is:
Type mismatch. Required List<Nothing>. Found List<IModel>.
Because the compiler doesn't know what masterTable can take in, it can't be sure that it could take in the IModel you're trying to pass into the getTableData method.

Run unit tests from abstract class in D?

I would like to run unit tests from the abstract class instead of from the concrete classes that inherit from it. I tried a few things that would not compile:
unittest(this T) { ... }
abstract class Parent(this T) : GrandParent
{
...
unittest
{
T x = new T();
x.something = true;
assert(x.something == true);
}
...
}
Is there something else I can do to de-duplicate the thousands of lines of unit tests that are otherwise going to exist for each child class?
If you're happy with a base class that's specialized (and thus duplicated) for each subclass:
abstract class Base(T) {
static assert(is(T : typeof(this)), "Tried to instantiate "~typeof(this).stringof~" with type parameter "~T.stringof);
unittest {
import std.stdio : writeln;
auto a = new T();
writeln(a.s);
}
}
class Derived : Base!Derived {
string s() {
return "a";
}
}
Instead of the static assert, I'd have preferred to have a template constraint on Base, but sadly this doesn't work (when the constraint is tested, we don't yet know if Derived inherits from Base!Derived, since that only happens after the constraint has passed, of course).
This pattern is known in C++ as Curiously Recurring Template Pattern (CRTP).