https://kotlinlang.org logo
#getting-started
Title
# getting-started
d

Draget

12/12/2021, 1:26 AM
I am confused about secondary constructors. Kotlint avoid having an incomplete object constructed by forcing me to immediatly call the primary constructor. But I do not know how I can actually calculate the value for the primary constructor - I want to run code to calculate the value, that is the whole point of the second constructor. I can do it by using a function:
Copy code
private data class MyClass(val intVal: Int) {
    constructor(stringVal: String) : this(someFunction(stringVal))
}

fun someFunction(stringVal: String): Int {
    println("I can run some random code here")
    val foo = stringVal.reversed()
    return foo.toInt()
}
But how could I run code on the secondary constructor without using a function?
e

ephemient

12/12/2021, 1:28 AM
note that Java has the same limitation, you cannot run any whole blocks of code before delegating to another constructor, only expressions
but in Kotlin, expressions are very expressive, and include things like
run { ... }
so you could, in theory, write
Copy code
private data class MyClass(val intVal: Int) {
    constructor(stringVal: String) : this(
        run {
            println("I can run some random code here")
            val foo = stringVal.reversed()
            return@run foo.toInt()
        }
    )
}
I thnk it's poor style, though
it would be more Kotlin-esque to have a constructor-like function,
Copy code
fun MyClass(stringVal: String) : MyClass {
    println("I can run some random code here")
    val foo = stringVal.reversed()
    return MyClass(foo.toInt())
}
d

Draget

12/12/2021, 9:45 AM
I see. Would this function live inside the class? I guess I should treat it like a factory method then.
e

ephemient

12/12/2021, 9:59 AM
no, outside
there is an alternative placement
Copy code
class MyClass private constructor(...) {
    companion object {
        operator fun invoke(...): MyClass {
            // arbitrary logic here
            return MyClass(...)
        }
    }
}
but I'd only use it in cases where the function outside doesn't work due to visibility
d

Draget

12/12/2021, 10:09 AM
Funny, I never realized this 'issue' in Java, because it is common to have a constructor that copies the values to an internal variable. Doing it like this allows multiple constructors initializing the Instance. In Kotlin it is made just way more visible that in this case, I have an uninitalized object in that moment. I guess I could do this in Kotlin:
Copy code
private data class MyClass(var intVal: Int) {
    constructor(stringVal: String) : this(0) {
        this.intVal = stringVal.toInt()
    }
}
But why would you conside a factory-like Method inside the class, bad style?
Copy code
private data class MyClass(var intVal: Int) {
    companion object {
        fun ofString(stringVal: String): MyClass = MyClass(stringVal.toInt())
    }
}
e

ephemient

12/12/2021, 5:50 PM
that's fine, although (depending on the use case) it may be more natural as an extension function,
Copy code
fun String.toMyClass(): MyClass
d

Draget

12/12/2021, 5:56 PM
In cases where I need this as a kind of helper in my current class, I usually use extension functions. But if I want the ability to be created from a String to be something of my class, it should be part of said class… at least that is what I would consider proper separation of concerns.
Thanks for the input. 🙂 I think I got a better feel for it now.
12 Views