Derived class initialisation order - kotlin

I'm currently working my way through the Kotlin docs for this section where they cover Derived class initialization order.
For the following snippet...
open class Base(val name: String) {
init { println("Initializing Base") }
open val size: Int = name.length.also { println("Initializing size in Base: $it") }
}
class Derived(
name: String,
val lastName: String
) : Base(name.capitalize().also { println("Argument for Base: $it") }) {
init { println("Initializing Derived") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in Derived: $it") }
}
fun main(args: Array<String>) {
println("Constructing Derived(\"hello\", \"world\")")
val d = Derived("hello", "world")
}
when executed it prints this:
Constructing Derived("hello", "world")
Argument for Base: Hello
Initializing Base
Initializing size in Base: 5
Initializing Derived
Initializing size in Derived: 10
My question is, why when override val size: Int = (super.size + lastName.length).also { println("Initializing size in Derived: $it") }
is executed does it not print Initializing size in Base: 5 again?
I would have thought it would print something like this:
Constructing Derived("hello", "world")
Argument for Base: Hello
Initializing Base
Initializing size in Base: 5
Initializing Derived
Initializing size in Base: 5 // Print because .also is called again ?
Initializing size in Derived: 10

You're initializing Base only once.
For that reason you're also initialising size only once.
For that reason you'll execute your also block only once.
Or, to answer your question in a different manner, it doesn't print Initializing size in Base second time, because it doesn't executes name.length.also { println("Initializing size in Base: $it") } second time.

Related

How to access to a specific init block in kotlin

I have a kotlin class with two initialization blocks. My constructor contains two parameters one of type list of String and another of boolean type which can be null.
I wish if I create an instance of my class with a single parameter (list of String) I can only execute the first initialization block and if I create an instance with the two parameters I can execute the second initialization block
class User(val type1: List<String>, val type2: Boolean?) {
init {
println("First initializer block executed ")
}
init {
println("Second initializer block executed ")
}
}
fun main() {
val list1: List<String> = listOf("One", "Two", "Three")
val user1 = User(list1,false)
}
how can i do it please ?
There's no need to have 2 inits. Just make a single init with logic inside to determine what to do. Like this for example:
class User(val type1: List<String>, val type2: Boolean? = null) {
init {
if (type2 == null) {
println("First initializer block executed ")
} else {
println("Second initializer block executed ")
}
}
}

Kotlin: How to define a variable whose type depends on the input?

I have a function in Kotlin which takes a particular string as input. Depending on the input, I want to create a variable of a specific type and do some computations on it.
For example,
fun compute(input: String): Any{
if(input=="2d"){
var point: Point2D;// Points2D - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-1"){
var point: Point2DWithP1AsOrigin;// Point2DWithP1AsOrigin - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-2"){
var point: Point2DWithP2AsOrigin;
//initilize and do some computations
return point.findDistanceFromOrigin()
}
.
.
.
}
You can see in the above example, I want to initilize the type of point depending on the input and do computation and return.
All the if-else conditions have the same code except for the definition of the variable. How can I put all this in a single block with something like this:
var point: if(input=="2d) Point2D::class else if(input=="2d-1") Point2DWithP1AsOrigin::class.....
How can I do that?
You could do something like this
fun compute(input: String): Any{
val point: MyPoint = when(input) {
"2d" -> Point2D()
"2d-1" -> Point2DWithP1AsOrigin()
"2d-2" -> Point2DWithP2AsOrigin()
else -> Point2D() //fallback is necessary
}
//initilize and do some computations
return point.findDistanceFromOrigin()
}
But then it's essential that all those classes share the same interface. Because they need to have the same methods in order to do the same operations on them.
For example like this:
class Point2D : MyPoint {
override fun findDistanceFromOrigin() = 5
}
class Point2DWithP1AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 6
}
class Point2DWithP2AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 7
}
interface MyPoint {
fun findDistanceFromOrigin() : Int
}
You can store constructor references and then invoke required one
fun main() {
val constructors = mapOf(
"2d" to ::Point2D,
"2d-1" to ::Point2DWithP1AsOrigin,
"2d-2" to ::Point2DWithP2AsOrigin,
)
val type = "2d-2"
val constructor = constructors[type] ?: throw IllegalArgumentException("$type not supported")
val point = constructor()
println(point::class)
}
Output
class Point2DWithP2AsOrigin

How do I create an instance of a Class passed as parameter to a function?

I'm building a library in Kotlin and here's my usecase
I have a base class
abstract class Component(...) {
// ... class body
}
I want the users of my library to define their own sub-classes like say:
class MyComponent() : Component() {
// .. class body
}
How can I write a helper function that takes in this derived class as a param and create an instance out of it. Something like:
fun helper(component: Class, props: HashMap<String, String>) : Component {
// somehow create a new instance of Class and return it?
}
Thanks!
You can have users pass a constructor reference:
fun helper(componentConstructor: ()->Component, props: Map<String, String>) : Component {
val component = componentConstructor()
// set it up and return it.
}
// usage:
val component = helper(::MyComponent, emptyMap())
Better for props not to require a specific type of map since it doesn’t matter here. Needless burden for users of your library.
abstract class Component(val prop1: String, val prop2: String) {
// ... class body
}
class MyComponent(prop1: String, prop2: String) : Component (prop1, prop2) {
// ... class body
}
fun helper(component: Class<MyComponent>, props: Map<String, String>): Component {
val constructor = component.constructors.first { it.parameterCount == props.size }
val arguments = props.values.toTypedArray()
return constructor.newInstance(*arguments) as Component
}
val instance = helper(MyComponent::class.java, mapOf("prop1" to "value1", "prop2" to "value2"))
println(instance.prop1 + ", " + instance.prop2) // Prints: value1, value2

How does nested covariance works in Kotlin?

Here's a code in which I'm having hard time understanding why the first compiles and second doesn't?
class Test11<T : Number> {
lateinit var test: MutableList<out T>.() -> Unit
}
fun main() {
val test: Test11<Int> = Test11<Int>()
val test2: Test11<out Number> = test
test.test.invoke(MutableList(3) { 55 }) // First
test2.test.invoke(MutableList(3) { 55 }) // Second
}
The second says MutableList<Nothing> was expected.
So basically in first case, T => Int so out out T => out Int => out Number maybe. In second case, T => out Number so anything which is subclass of Number, then still out T => out Number right?
I'm not able to understand why doesn't it work by that logic...
The MutableList is a function parameter. You'd have the exact same issue with:
class Test11<T : Number> {
fun test(list: MutableList<out T>) {
}
}
fun main() {
val test: Test11<Number> = Test11<Number>()
val test2: Test11<out Number> = test
test.test(MutableList(3) { 55 }) // First
test2.test(MutableList(3) { 55 }) // Second
}
A covariant type by definition prevents functions where the type is a parameter from being called, but this also logically extends to nested covariance of the same type. If T is covariant (for the class), then it is not any more safe to consume an object that can produce Ts than to consume Ts directly.
Example of how this could create a failure:
class Test11<T : Number> {
var list: MutableList<out T>? = null
fun test(list: MutableList<out T>) {
this.list = list
}
}
fun main() {
val test: Test11<Long> = Test11()
val test2: Test11<out Number> = test
val doubleList: MutableList<out Number> = mutableListOf(1.0)
test2.test(doubleList) // Not allowed
// if it were allowed:
val long: Long? = test.list?.firstOrNull() // ClassCastException casting the Double to a Long
}

Destructuring instead of .bind() doesn't work in an Arrow Monad comprehension

According to Arrow's Javadoc there are three ways of binding over a monad:
/**
* All possible approaches to running [Kind] in the context of [Fx]
*
* ```
* fx {
* val one = just(1).bind() // using bind
* val (two) = just(one + 1) // using destructuring
* val three = !just(two + 1) // yelling at it
* }
* ```
*/
The first one and the last one work fine however for some reason destructuring doesn't, why?
In the next sample you can see I'm using destructuring, val (j) = helloJoey().k(),) but that value is interpreted as a Mono` instead of a String.
class HelloServiceImpl : HelloService {
private val logger = LoggerFactory.getLogger(javaClass)
override fun helloEverybody(): Mono<out String> {
return MonoK.monad().fx.monad {
val (j) = helloJoey().k()
val a = !Mono.zip(helloJohn(), helloMary()).map { "${it.t1} and ${it.t2}" }.k()
"$j and $a"
}.fix().mono
}
override fun helloJoey(): Mono<String> {
return Mono.defer {
logger.info("helloJoey()")
sleep(2000)
logger.info("helloJoey() - ready")
Mono.just("hello Joey")
}.subscribeOn(Schedulers.elastic())
}
override fun helloJohn(): Mono<String> {
return Mono.defer {
logger.info("helloJohn()")
sleep(5000)
logger.info("helloJohn() - ready")
Mono.just("hello John")
}.subscribeOn(Schedulers.elastic())
}
override fun helloMary(): Mono<String> {
return Mono.defer {
logger.info("helloMary()")
sleep(5000)
logger.info("helloMary() - ready")
Mono.just("hello Mary")
}.subscribeOn(Schedulers.elastic())
}
}
fun main() {
val countDownLatch = CountDownLatch(1)
HelloServiceImpl().helloEverybody().subscribe {
println(it)
countDownLatch.countDown()
}
countDownLatch.await()
}
This is a known problem and why we're moving away from this approach. They're marked as deprecated here.
What happens is, a MonoK is a data class for which the destructure operator is already defined as returning the wrapped Mono. When used inside an fx block this destructuring takes precedence over the one defined on BindSyntax. Check and see if hinting your expected type works, otherwise use invoke or bind instead.