Override generic method in abstract class with concrete type in subclass - kotlin

I have an main class in Kotlin which defines one concrete and one abstract generic method as follows:
abstract class MainClass {
abstract fun <TParent, TChild> getChildren(parent: TParent): Array<TChild>?
fun <TParent, TChild> processChildren(parent: TParent) {
val children = getChildren<TParent, TChild>(parent)
// ... do something with children
}
}
As you can see the method is about a parent object of type TParent containing child objects of type TChild. The parent class and how to get the children from it should be defined by subclasses, which should provide the concrete types.
I did the following:
class MyClass : MainClass{
override fun getChildren(parent: MyParent): Array<MyChild>? {
//... some logic getting the children from a parent object
}
}
But that does not work because it won't compile ('getChildren' overrides nothing).
How can I define a generic abstract method and implement it with concrete types in a subclass? Note that it is important to me that the generic types are defined on method-level, not on class level!

You cannot do this. Due to the type erasure the methods signatures will not fit.
What you actually can do is to make this abstract method protected and overload it with some specific types
// protected abstract fun <TParent, TChild> getChildren...
class MyClass: MainClass() {
override fun <TParent, TChild> getChildren(parent: TParent): ArrayList<MyChild>? {
// Some dummy implementation
println(parent!!::class.java.canonicalName)
return null
}
fun getChildren(parent: MyParent): ArrayList<MyChild>? {
return getChildren<MyParent, MyChild>(parent)
}
fun getChildren(parent: MyParent2): ArrayList<MyChild2>? {
return getChildren<MyParent2, MyChild2>(parent)
}
}
But not really sure what is the sense of doing this especially if generic types are not bounded

Looks like you don't want the method in one class to process different types of parameters.
In this scenario, make the class generic:
abstract <TParent, TChild> class MainClass {
abstract fun getChildren(parent: TParent): Array<TChild>?
fun processChildren(parent: TParent) {
val children = getChildren<TParent, TChild>(parent)
// ... do something with children
}
}
class MyClass : MainClass<MyParent, MyChild>() {
override fun getChildren(parent: MyParent): Array<MyChild>? {
//... some logic getting the children from a parent object
}
}

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()
}

How to get a type parameter's class name?

I have a base class:
abstract class JSONDeserializationStrategy<T : Any>: DeserializationStrategy<T> {
protected abstract fun parse(json: JsonObject): T
protected abstract fun getSerializationException(): SerializationException
}
and then a derived class
class MyClassParserDeserializationStrategy : JSONDeserializationStrategy<MyClass>() {
override val descriptor: SerialDescriptor
= buildClassSerialDescriptor("MyClass")
override fun getSerializationException(): SerializationException
= throw SerializationException("Invalid JSON received for MyClass.")
How could I move the property descriptor and the method getSerializationException from the derived class into the base class, since they only "adapt" by providing their name as String? I was trying to do something in the direction of T::class.java.simpleName as String but it didnt work. What is the best way to do this?
As #Tenfour04 explained, T is erased, so it is not directly accessible. However, as long as the subclass of JSONDeserializationStrategy provides the T as a specific class/type, it can be acquired with a bit of reflection voodoo:
fun main() {
val strategy = MyClassParserDeserializationStrategy()
println(strategy.descriptor.serialName) // MyClass
}
abstract class JSONDeserializationStrategy<T : Any>: DeserializationStrategy<T> {
protected val type: KType = this::class.supertypes
.first { it.classifier == JSONDeserializationStrategy::class }
.arguments[0].type!!
#Suppress("UNCHECKED_CAST")
protected val typeClass = requireNotNull(type.classifier as? KClass<T>) {
"T is unknown"
}
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(typeClass.simpleName!!)
fun getSerializationException(): SerializationException =
throw SerializationException("Invalid JSON received for ${typeClass.simpleName!!}.")
...
}
I'm not 100% sure, but I believe both type!! and simpleName!! are safe, they can't be null.
Also, it won't work if T is really fully erased and unknown, e.g.:
val strategy = GenericParserDeserializationStrategy<MyClass>() // exception
For this reason it makes sense to open type/typeClass properties for overriding, so generic non-abstract subclasses could provide their own means to acquire T. However, then we would probably need to move the initialization of most of properties outside of the constructor.
Because of type erasure, T's class is not accessible. Work-around could be to add it as a constructor property that returns the type, and then the subclasses must pass the type. The property needs to be in the constructor, rather than provided as an abstract property for subclasses to override because you need it to initialize descriptor at instantiation time. (It's highly discouraged to call an open property at class initialization time.)
abstract class JSONDeserializationStrategy<T : Any>(protected val typeClass: KClass<out T>): DeserializationStrategy<T> {
protected abstract fun parse(json: JsonObject): T
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(typeClass.simpleName!!)
fun getSerializationException(): SerializationException =
throw SerializationException("Invalid JSON received for ${typeClass.simpleName}.")
}
class TodaySaleParserDeserializationStrategy : JSONDeserializationStrategy<TodaySale>(TodaySale::class) {
}

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.

How do you resolve circular imports in Kotlin

I'm new to programming in Kotlin and I've already managed to run into the classic circular dependency issue - I know Kotlin can cope with those but I'd like to know how would I go about changing my design to avoid it. What structures or Kotlin functionality should I use in the following?
import MyClass
interface MyInterface {
fun useMyClass(myInstance: MyClass)
}
import MyInterface
class MyClass(myList: List<MyInterface>) {
val storedList: List<MyInterface> = myList
var myValue: Int = 10
}
I would like MyClass to store multiple objects which implement MyInterface, but I would also like each of those objects to reference the class they have been passed to, i.e. each call of useMyClass would have the signature of useMyClass(this).
For example, I could create a class
class ImplementingMyInterfaceClass(): MyInterface {
override fun useMyClass(myInstance: MyClass) {
myInstance.myValue += 10
}
}
and call it somewhere within MyClass:
ImplementingMyInterfaceClass().useMyClass(this)
Technically I could create another construct in the middle which would be used by MyInterface and inherited/implemented by MyClass, but this just doesn't feel correct. Any suggestions?
Note: In my specific issue, it might be helpful to consider each implementation of MyInterface as a sort of a "modifier" (since it will modify the instance of the class) - MyClass instances should be aware of its modifiers and each modifier should be able to modify that instance.
It's going to largely depend on what the interface has to do, but you could limit its function argument to some interface that MyClass implements:
interface MyInterface {
fun increaseSomeValue(someValueHolder: MySubInterface)
interface MySubInterface {
var myValue: Int
}
}
class MyClass(myList: List<MyInterface>): MyInterface.MySubInterface {
val storedList: List<myInterface> = myList
override var myValue: Int = 10
}
Or your interface can take a property argument:
interface MyInterface {
fun increaseSomeValue(someValue: KMutableProperty<Int>)
}
class MyInterfaceImpl: MyInterface {
override fun increaseSomeValue(someValue: KMutableProperty<Int>) {
someValue.setter.call(someValue.getter.call() + 10)
}
}
// from MyClass:
storedList.first().printSomeValue(::myValue)
In other cases where we don't need to both get and set, it could be cleaner to take a more versatile function argument (lambdas could be passed):
interface MyInterface {
fun printSomeValue(valueProvider: () -> Int)
}
class MyInterfaceImpl: MyInterface {
override fun printSomeValue(valueProvider: () -> Int) {
println(valueProvider())
}
}
// from MyClass:
storedList.first().printSomeValue(::myValue)
// or
storedList.first().printSomeValue { 1..10.random() }

Kotlin immutable field is null when called

This is the code snippet:
abstract class SuperClass {
init {
toOverride()
}
abstract fun toOverride()
}
class ChildClass : SuperClass() {
private val innerClass = InnerClass()
override fun toOverride() {
innerClass.doSomething()
}
class InnerClass {
fun doSomething() = Unit
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val superClass = ChildClass()
superClass.toOverride()
}
}
Calling superClass.toOverride() will cause null pointer exception but from ChildClass point of view innerClass is an immutable field. The problem is that in the constructor of SuperClass toOverride() is being called.
We don't have control over how SuperClass is written in a lot of cases. In android framework there is a lot of such cases, for example http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/view/View.java#20160 will be called in the constructor of View.java. How do we address those issues? Adding null checks will trigger IDE warning and looks like kotlin compiler will trim the null check sometimes if you use ?. operator since it think the ?. is not necessary.
To start with, I'd read What's wrong with overridable method calls in constructors?
With that out of the way, and if you really can't control what the parent class does and you really really need it to do what it's doing, you can probably do something like this (Only showing the ChildClass:
class ChildClass : SuperClass() {
private val innerClass: InnerClass? = InnerClass()
init {
// beware: this is ONLY done because toOverride ONLY calls
// innerClass.doSomething(), you have to make sure that anything else
// there is idempotent
toOverride()
}
override fun toOverride() {
innerClass?.doSomething()
}
}
My recommendation would be to think if there's an alternative implementation to your class hierarchy.