Instantiate child class with values of existing parent class - kotlin

I want to transfer the values of an existing parent class to a new child. If possible without reflection.
Another possible solution could be if I could "cast" the class to the child class.
This is a simplified example of what I want to achieve.
open class Dog {
var height = -1
}
class Dalmatian: Dog() {
var dots = -1
}
fun main() {
val dog: Any = Dog().apply {
height = 24
}
// Doesn't work
val dalmatian = (dog as Dalmatian).apply {
dots = 101
}
}

There's no built-in way to convert classes to a subtype. In your case, you could just make a method:
class Dog(var height: Int = -1)
class Dalmation(height: Int = -1, var dots: Int = 24): Dog(height) {
companion object {
fun fromDog(dog: Dog, dots: Int) = Dalmation(dog.height, dots)
}
}
You can then convert:
fun main() {
val dog = Dog()
val dalmation = Dalmation.fromDog(dog, 24)
}
and you can cast only if the Dog is already a Dalmation:
fun main() {
val dog: Dog = Dalmatian()
val dalmatian: Dalmatian = dog as Dalmatian
// but not this
val dalmatian: Dalmatian = Dog() as Dalmatian
}

Related

Expecting member declaration while creating class and constructor

I am newbie in kotlin, I trying to apply lesson on oop on kotlin, but I got multiple "Expecting member declaration"
I don't know where's error in this code
open class Car( open val color:String?=null, open val brand:String?=null) {
open fun speed(){
println("max speed is 220")
}
}
class Toyota() : Car() {
override color = "White"
override brand = "Toyota"
override fun speed(){
println("max speed is 360")
}
}
fun main() {
var car:Toyota = Toyota()
car.speed()
}
You are missing a val keyword in both parameters in Toyota class:
class Toyota() : Car() {
override val color = "White"
override val brand = "Toyota"
override fun speed(){
println("max speed is 360")
}
}
Or you can do it even better by using Car constructor directly:
class Toyota : Car(color = "White", brand = "Toyota") {
override fun speed(){
println("max speed is 360")
}
}
With this approach you can even make Car simpler (no need for open keyword on your properties):
open class Car(val color : String? = null, val brand : String? = null) {
open fun speed(){
println("max speed is 220")
}
}
You could override color and brand in the constructor of the subclass:
class Toyota(override val color: String = "White", override val brand: String = "White") : Car() {
override fun speed() {
println("max speed is 360")
}
}

How to solve this strong dependency between those classes?

I have two classes A and B.
Class A has several properties. One of them are an instance of class B.
At some point in the main function I will define an instance a of A. I will need to do some computation on its property of type B.
This computation, however, needs another property of a.
The result is a.property3.computation(a.property1,someValue). I think it's ugly.
Here is some "pseudo-code" (in Kotlin but I am facing the same problem using other languages as well):
class B {
val property : Map<String,Int>
fun computation(val parameter1: Int, val parametre2: Double) : Int {
//doing some computation
return result
}
}
class A {
var property1 : Int
var property2 : Stirng
var property3 : B
}
fun main (){
val someValue = 0.4 //It's here to show the idea that the function `computation` needs also some other arguments that does not come from `A`'s propery
val a = A()
val result = a.property3.computation(a.property1,someValue) // here is the line that bothers me !
}
I think you should use Builder design pattern to remove computation function from B class like this:
class B {
val properties : MutableMap<String,Int> = HashMap()
fun setProperty(name: String, value: Int) {
this.properties[name] = value
}
}
class A {
var property1 : Int = 0
var property2 : String = ""
var property3 : B = B()
}
class Calculator(builder: Builder) {
private val property1 = builder.property1
private val someValue = builder.someValue
private val properties = builder.properties
companion object {
fun builder() = Builder()
}
fun computation() : Int {
//doing some computation
val result = property1 + someValue.toInt() + properties.getOrDefault("value", 0)
return result
}
class Builder {
var property1: Int = 0
var someValue: Double = 0.0;
var properties : MutableMap<String,Int> = HashMap()
fun property1(property1: Int): Builder {
this.property1 = property1
return this
}
fun someValue(someValue: Double): Builder {
this.someValue = someValue
return this
}
fun properties(properties : Map<String,Int>): Builder {
this.properties.putAll(properties);
return this
}
fun build(): Calculator {
return Calculator(this)
}
}
}
fun main (){
val someValue = 0.4 //It's here to show the idea that the function `computation` needs also some other arguments that does not come from `A`'s propery
val a = A()
a.property1 = 10
a.property3.setProperty("value", 20)
val result = Calculator.builder()
.properties(a.property3.properties)
.property1(a.property1)
.someValue(someValue)
.build()
.computation()
println(result)
}
May be you want this?
fun main (){
val someValue = 0.4
val a = A()
val result = with(a) {
property3.computation(property1,someValue)
}
}

Why protected var is KProperty and public/private var is KMutableProperty?

In each of the following cases I have some mutable var properties. According to Javadocs mutable properties are represented by KMutableProperty but in these examples protected property is represented by KProperty class. Why is that so?
class FooA {
var publicProp: String? = null
protected var protectedProp: String? = null
private var privateProp: String? = null
fun foo() {
val a = ::publicProp
val b = ::protectedProp
val c = ::privateProp
}
}
open class FooB {
var publicProp: String? = null
protected var protectedProp: String? = null
private var privateProp: String? = null
fun foo() {
val a = ::publicProp
val b = ::protectedProp
val c = ::privateProp
}
}
class Bar : FooB() {
fun bar() {
val a = ::publicProp
val b = ::protectedProp
}
}
Type hints from IDEA

Handling lists of two different types with same code using functional programming in kotlin

I have two lists with different types list1 and list2 . I have a method which does the same operation on the lists.
I'm using lambdas where I cannot access the property as (it.prop1) if I'm using List of type Any.
Is there any solution to avoid this issue with lambdas?
val list1: List<Student> = ..
val list2: List<Teacher> = ..
list1.filter {
school.contains(it.prop1) }
.forEach {
total += it.prop2.toLong()
}
list2.filter {
school.contains(it.prop1) }
.forEach {
total += it.prop2.toLong()
}
Thanks.
Try this:
object Test {
private fun isContains(school: Set<Int>, any: Any) = when (any) {
is Student -> school.contains(any.prop1)
is Teacher -> school.contains(any.prop1)
else -> false
}
private fun value(any: Any) = when (any) {
is Student -> any.prop2
is Teacher -> any.prop2
else -> throw NoWhenBranchMatchedException("any should be Student or Teacher")
}
#JvmStatic
fun main(args: Array<String>) {
val school = setOf(1, 2)
val list = listOf(Student(1, 1), Student(2, 2), Student(3, 3), Teacher(1, 1), Teacher(2, 2), Teacher(3, 3))
val total = list.filter {
isContains(school, it)
}.map {
value(it)
}.sum()
println("Total: $total")
}
private class Student(val prop1: Int, val prop2: Int)
private class Teacher(val prop1: Int, val prop2: Int)
}
You may use Type Checks and Casts
class Student(val prop1:Int, val prop2:Int)
class Teacher(val prop1:Int, val prop2:Int)
val list : List<Any> = listOf(Student(1,1),Student(2,2),Student(3,3),Teacher(1,1),Teacher(2,2),Teacher(3,3))
var total : Long = 0
val school : Array<Int> = arrayOf(1,2)
list.filter{
if(it is Student)
{
school.contains((it as Student).prop1)
}
else if(it is Teacher)
{
school.contains((it as Teacher).prop1)
}
else
{
false
}
}.forEach{
if(it is Student)
{
total += (it as Student).prop2.toLong()
}
else if(it is Teacher)
{
total += (it as Teacher).prop2.toLong()
}
}
println(total) //print 6 in this example
This is ugly tough. It is better to make Student and Teacher either inherit a common superclass or implement a common interface
As far as I know you can't. You can take advantage of common interface.
For example:
interface Human{
val age: Int
}
class Student(override val age: Int): Human
class Teacher(override val age: Int, val salary: Double):Human
fun x(){
val list1: List<Student> = ...
val list2: List<Teacher> = ...
val school: List<Human> = ...
val result = school
.filter { it is Student }
.sumBy { it.age}
val result2 = school
.filter { it is Teacher }
.sumBy { it.age }
}

Kotlin - Factory Function for Class with Private Constructor

In Kotlin, is it possible to have a factory function that creates an instance of a class with a private constructor?
My goal is to enforce the factory function to be used and to prevent instantiation via the class's constructor.
Example:
// factory function, valid
val myInstance = myClassOf()
// class instantiation, invalid
val myInstance = MyClass()
I'm trying to mimic the behavior of some of the built-in factory functions like intArrayOf(), e.g.
// works
val myIntArray = intArrayOf()
// not possible as IntArray has a private constructor
val myIntArray = IntArray()
You can use companion object in this way:
class MyClass private constructor() {
companion object {
operator fun invoke() = MyClass()
}
}
val myInstance = MyClass() // Calls the factory function invoke()
Name the factory function if it has a special meaning. For example:
class MyClass private constructor(values: List<String>) {
companion object {
fun of(vararg values: String) = MyClass(values.toList())
}
}
val myInstance = MyClass.of("first", "second")
You can do something like this:
import MyClass.Companion.myClassOf
class MyClass private constructor() {
companion object {
fun myClassOf() = MyClass()
}
}
//val myInstance1 = MyClass() // not allowed
val myInstance2 = myClassOf()
Try Builder instead.
class FoodOrder private constructor(
val bread: String?,
val condiments: String?,
val meat: String?,
val fish: String?) {
data class Builder(
var bread: String? = null,
var condiments: String? = null,
var meat: String? = null,
var fish: String? = null) {
fun bread(bread: String) = apply { this.bread = bread }
fun condiments(condiments: String) = apply { this.condiments = condiments }
fun meat(meat: String) = apply { this.meat = meat }
fun fish(fish: String) = apply { this.fish = fish }
fun build() = FoodOrder(bread, condiments, meat, fish)
}
}
Reference: https://www.baeldung.com/kotlin-builder-pattern