Kotlin Inheritance - Create child instance using parent contructor - kotlin

Considering the the parent class:
abstract class Parent(
val arg1: TypeArg1 = defValue,
val arg2: TypeArg2 = defValue,
....
)
and
class Child : Parent()
Is there anyway in Kotlin to create a Child instance using Parent constructor? Like:
val child = Child(arg1, arg2)
I want to avoid doing the proxy like:
class Child(
val arg1: TypeArg1 = defValue,
val arg2: TypeArg2 = defValue,
) : Parent(arg1, arg2)
I inherit Parent in many classes and doing a such a declaration of Child constructor is really unnecessary.
Is there any way to avoid this and just create the instance of child using its parent construcor.

The language doesn't have an automated way, but IntelliJ IDEA can auto-generate it for you.
Type
class Child: Parent()
and then press Alt + Enter and it will give the option to Add constructor parameter(s) ___....

Related

Why it is forbidden to use 'out' keyword in generics if a method excepts the type parameter as a parameter?

I'm looking for an example that can cause a problem when using out in class declaration and the class has a method that get the parameter type as argument.
Also I'm looking for an example that can cause a problem when using in in class declaration and the parameter type is a var member of the class?
I think that i will be able to understand the rules only by examples
Suppose these are the classes we are working with:
open class Animal
class Cat: Animal() {
fun meow() = println("meow")
}
If we create a class like this with covariant out type and the compiler allowed us to use the type as a function parameter:
class Foo<out T: Animal> {
private var animal: T? = null
fun consumeValue(x: T) { // NOT ALLOWED
animal = x
}
fun produceValue(): T? {
return animal
}
}
Then if you do this, it will be lead to an impossible situation where we are trying to call meow on an Animal that doesn't have a meow function:
val catConsumer = Foo<Cat>()
val animalConsumer: Foo<Animal> = catConsumer // upcasting is valid for covariant type
animalConsumer.consumeValue(Animal())
catConsumer.produceValue()?.meow() // can't call `meow` on plain Animal
And if we create a class like this with contravariant in type and the compiler allowed us to use the type as a return value:
class Bar<in T: Animal>(private val library: List<T>) {
fun produceValue(): T { // NOT ALLOWED
return library.random()
}
}
Then if you do this, it will lead to the compiler impossibly casting a return type to a subtype.
val animalProducer: Bar<Animal> = Bar(List(5) { Animal() })
val catProducer: Bar<Cat> = animalProducer // downcasting is valid for contravariant type
catProducer.produceValue().meow() // can't call `meow` on plain Animal
A property has a getter which is just like a function that returns a value, and a var property additionally has a setter, which is just like a function that takes a parameter. So val properties are not compatible with contravariance (in) and var properties are not compatible with contravariance or covariance (out). Private properties aren't encumbered by these restrictions because within the class's inner workings, the type is invariant. All the class can know about its own type is its bounds. Variance just affects how the class can be cast (viewed) by the outside world.
So an example with val is enough to show why any property is incompatible with contravariance. You could replace val with var below and it would be no different.
class Bar<in T: Animal>(
val animal: T // NOT ALLOWED
)
val animalProducer: Bar<Animal> = Bar(Animal())
val catProducer: Bar<Cat> = animalProducer // downcasting is valid for contravariant type
catProducer.animal.meow() // can't call `meow` on plain Animal
Small reminder about variance
When you have a generic class G<T> (parameterized type), the variance is about defining a relationship between the hierarchy of the types G<T> for different Ts, and the hierarchy of the different Ts themselves.
For instance, if child class C extends a parent P then:
does List<C> extend List<P>? (List<T> would be covariant in T)
or the reverse? (contravariant)
or is there no relationship between List<C> and List<P>? (invariant).
Example
Now, consider List<out T>, which means that List is covariant in T.
As we've just seen, declaring list as such means that the following holds: "if C extends P, then List<C> extends List<P>".
Let's assume the following class declarations here:
open class Parent {
fun doParentStuff()
}
class Child : Parent() {
fun doChildStuff()
}
The covariance of List<out T> means that this is possible:
val listOfChild: List<Child> = listOf<Child>(Child(), Child())
// this is ok because List is covariant in T (out T)
// so List<Child> is a subtype of List<Parent>, and can be assigned to listOfParent
val listOfParent: List<Parent> = listOfChild
So what would happen if we could declare a method in the List class that accepts a parameter T?
class List<out T> {
fun add(element: T) {
// I can guarantee here that I have an instance of T, right?
}
}
The rules of most languages (including Kotlin) state that if a method accepts a parameter of type T, you can technically get an instance of T or any subclass of T (this is the point of subclassing), but you have at least all the API of T available to you.
But remember that we declared List<out T>, which means I can do:
val listOfChild: List<Child> = listOf<Child>(Child(), Child())
// this is ok because List is covariant in T (out T)
val listOfParent: List<Parent> = listOfChild
// listOfChild and listOfParent point to the same list instance
// so here we are effectively adding a Parent instance to the listOfChild
listOfParent.add(Parent())
// oops, the last one is not an instance of Child, bad things will happen here
// we could fail right here at runtime because Parent cannot be cast to Child
val child: Child = listOfChild.last
// even worse, look at what looks possible, but is not:
child.doChildThing()
Here you can see that from within the List<Child> instance, we actually could receive an instance of Parent which is not a subclass of Child in a method that had declared a parameter of type Child.

Kotlin data class secondary constructor init block

Let's imagine that we have data class with two properties and we need secondary constructor for some reasons. Problem is that i need recalculate each argument in primary constructor call instead of using some cached value of raw.split("_"):
data class Id(
val arg1: String,
val arg2: String
) {
constructor(raw: String) : this(raw.split("_")[0], raw.split("_")[1])
}
I can do this in Java but how I can do this in Kotlin?
You can do it this way:
data class Id(
val arg1: String,
val arg2: String
) {
private constructor(splitted: List<String>) : this(splitted[0], splitted[1])
constructor(raw: String) : this(raw.split("_"))
}
It's a good and idiomatic way to solve your problem. Since all secondary constructors must delegate to primary constructor (data class always has it), you can't do what you want in constructor body. In Java it works because there are no primary constructors and no data classes at language level - in Kotlin you can do it like in Java too if you remove data modifier and move properties outside of constructor, but it's a really bad way.

Is it possible to extend a base class in a data class without overriding parameters?

I have a simple inheritance tree in my Kotlin project, where a base class is extended by a data class. I cannot declare construction of my data class without overriding the parameters from the base class
I've noticed that this would work if I wasn't extending in a data class:
open class Base(
val first: String,
val second: String
)
class Child(
first: String,
second: String,
val third: List<String>
) : Base(first, second)
This is what I ended up with currently:
open class Base(
open val first: String,
open val second: String
)
data class Child(
override val first: String,
override val second: String,
val third: List<String>
) : Base(first, second)
But I would like to be able not to override the constructor parameters, because I'm not really overriding them. I just need to take them in my Child constructor to be able to pass them to Base.
Having a base class like this and a derived data class, you have to override its properties or separate them, because all primary constructor parameters of a data class must also be declared as properties:
— All primary constructor parameters need to be marked as val or var;
However, based on what your goal really is, you can transform your code in one of the following ways:
Declare the properties in Child as separate, unrelated properties:
open class Base(
open val first: String,
open val second: String
)
data class Child(
val childFirst: String,
val childSecond: String,
val third: List<String>
) : Base(childFirst, childSecond)
This will allow you to have separate implementations for the properties if you need it, storing the values passed as childFirst and childSecond in the Child and probably altering them in some way in the implementation of Base.
Make Base an interface:
interface Base {
val first: String,
val second: String
}
data class Child(
override val first: String,
override val second: String,
val third: List<String>
) : Base
This ensures that Base doesn't have an implementation that stores property values in addition to the Child's properties with backing fields (those will consume additional memory, but, as the propeties are overridden, Base will consistently see the values of the Child's backing fields as first and second).
Make Base an abstract class with abstract properties:
abstract class Base {
abstract val first: String,
abstract val second: String
}
data class Child(
override val first: String,
override val second: String,
val third: List<String>
) : Base()
This follows a similar purpose: Base won't store the property values in its implementation needlessly duplicating the properties of Child.
Make Child a normal class, manually implementing those of the functions that are generated for data classes which you actually need.

Support deserialization of inheritance chained objects in kotlin with jackson

Assume we need to comply deserialization of such object inheritance structure:
open class Parent(
#JsonProperty("parent_value")
val parentValue: String = "default"
)
class Child(
#JsonProperty("child_value")
val childValue: String) : Parent()
Both parent & child object define own fields and #JsonProperty over it.
Also i have a test to check deserialization:
#Test
fun testDeserializeWithInheritance() {
val map = mapOf("child_value" to "success", "parent_value" to "success")
val jsonResult = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(map)
println("serialized object: $jsonResult")
val deserialized: JsonConverterModuleTest.Child = objectMapper.readValue(jsonResult)
println("deserialized object: withdraw=${deserialized.childValue} parentValue = ${deserialized.parentValue}, exchangeFrom = ${deserialized.parentValue}")
assertEquals("success", deserialized.childValue)
assertEquals("success", deserialized.parentValue)
}
But a problem is the test fails with error:
serialized object: { "child_value" : "success", "parent_value" :
"success" }
org.junit.ComparisonFailure: parent value not equal:
Expected:success
Actual :default
How to deserialize the child object properly? The main goal is to not duplicate fields nor #JsonProperty annotations in child class.
I have a solution for the issue, but open to accept better one
The issue happens because annotation over constructor field is not applied to field nor getter automatically (kotlin mechanizm). Also Seems that it is not processed on deserialization of a child object.
Jackson supports annotations over field or over getter methods, so an appropriate solutions are either
open class Parent(
#get:JsonProperty("parent_value")
val parentValue: String = "default"
)
or
open class Parent(
#field:JsonProperty("parent_value")
val parentValue: String = "default"
)
With this the test completes

Kotlin optional generic parameter

Here is the problem I am trying to resolve, I am trying to use a void type as a generic type:
class Parent {
private abstract class Item<out T>(val data: T)
// This subclass should contain data
private class ItemContent(val data: String): Item<String>(data)
// This subclass doesn't contain data
private class ItemNoContent: Item<Any?>(null)
}
Some base classes like ItemNoContent doesn't contain meaningful data so I make ItemNoContent extends Item(null). It works but I feel that the use of Any? and null is inappropriate here. Is there a more Kotlin way to solve this optional generic problem?
You can also use Item<Unit>(Unit) which represents a void value in Kotlin.
Some base classes like ItemNoContent doesn't contain meaningful data
Then why extend a class which is supposed to have it? While Unit and null are both options, consider also
private abstract class Item<out T>
private abstract class ItemWithContent<out T>(val data: T) : Item<T>
...
// object may make more sense than class here
private object ItemNoContent : Item<Nothing>()
I would tweak the inheritance like this:
abstract class Item
abstract class ItemWithContent<T>(val d: T): Item()
class ItemWithStringContent(d: String): ItemWithContent<String>(d)
class ItemWithNoContent: Item()
This way, there is not need to use Unit or Nothing.
Usage:
fun main(args: Array<String>){
val t: Item = ItemWithStringContent("test")
println((t as? ItemWithStringContent)?.d)
}