How to access to a specific init block in kotlin - 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 ")
}
}
}

Related

Call reflected constructor with default parameters in Kotlin

I'm restoring complex data from json files and some of them requires call for specific types that does not have empty constructors, but constructors with default parameters.
There is a method for creation an empty object,
abstract class Restorer {
inline fun <reified T>load(ctx: T): T {
var that: T = reset(ctx)
// ...
}
inline fun <reified T>reset(ctx: T): T {
val primaryConstructorT = T::class.constructors.find {
it.parameters.isEmpty() || it.parameters.all { prm -> prm.isOptional }
}
return primaryConstructorT!!.call() // <--- here is a problem
}
}
So in some cases primaryConstructorT is a reflection for constructor with optional params, but direct call for that produces an exception.
Callable expects 2 arguments, but 0 were provided.
There is the case for creation simple data class
data class DataClass (val foo: List<String> = listOf(), val bar: List<Int> = listOf())
// ...
var context: DataClass? = null;
// ...
context = Restorer.load(context)
Is there any method to call it
Maybe there is a better way, but you can use callBy() with an empty map:
return primaryConstructorT!!.callBy(emptyMap())
It automatically replaces missing parameters with their defaults.

Which kotlin language feature is this

I'm learning about the kotlin DSL, specifically with Teamcity and I see an initialization pattern I don't really understand yet
Kotlin playgound link
Here is the code
package org.arhan.kotlin
fun main() {
val project = project {
configuration {
step {
name = "step 1"
command = "hi"
}
customstep {
name = "flang"
anotherCommand = "derp"
command = "1111"
}
}
}
println(project.configurations[0].steps[1].command)
}
fun project(block: Project.() -> Unit): Project {
return Project().apply(block)
}
fun Project.configuration(block: Configuration.() -> Unit): Configuration {
val configuration = Configuration().apply(block)
configurations.add(configuration)
return configuration
}
fun Configuration.step(block: Step.() -> Unit): Step {
val step = Step().apply(block)
steps.add(step)
return step
}
class Project {
var configurations = mutableListOf<Configuration>()
fun build(block: Configuration.() -> Unit) = Configuration().apply(block)
}
class Configuration {
var steps = mutableListOf<Step>()
}
open class Step {
final lateinit var name: String
var command: String = ""
}
open class CustomStep(): Step(){
var anotherCommand: String = ""
constructor(init: CustomStep.() -> Unit): this(){
// what does this do?
init()
}
}
fun Configuration.customstep(block: CustomStep.() -> Unit): Step {
// how is this constructor initialized
val step = CustomStep(block)
steps.add(step)
return step
}
Specifically the question is about how the CustomStep class is initialized. It take's in a lambda with CustomStep as the reciever (is this the correct terminology?).
And then I call init() in the constructor, which initializes the newly created CustomStep based on the block that was passed in.
I'm not sure how that initialization works. Or rather, which specific Kotlin language feature is being used here.
And how is this different if instead I wrote it the following way?
open class CustomStep(): Step(){
var anotherCommand: String = ""
// no constructor
}
fun Configuration.customstep(block: CustomStep.() -> Unit): Step {
// use apply vs. passing in the block
val step = CustomStep().apply(block)
steps.add(step)
return step
}
Thank you
The init() is referring to the parameter init: CustomStep.() -> Unit:
constructor(init: CustomStep.() -> Unit): this(){
// vvvv ^^^^
init()
}
You are simply calling what you passed in, on this. init needs a CustomStep as receiver after all. As with most situations when calling something on this, this can be omitted, which is what happens here. In the case of customStep, you passed in block.
val step = CustomStep(block)
block is this bit from main:
{
name = "flang"
anotherCommand = "derp"
command = "1111"
}
Your alternative of CustomStep().apply(block) is the same too. Calling the secondary constructor that you declared will first call the parameterless primary constructor, as you have declared as : this(), and is required. This is the same as CustomStep(). Then both versions call block on this.

Is there a way to define an implicit ctor for a Kotlin class?

as the title says it, is there any way to define a constructor or convertion for a class/object that can be called implicitly like this?
class Person {
val name: String
val mood: Mood = Mood.Happy
fun toString(): String = "$name is $mood"
}
fun main() {
// Calls the magic implicit ctor
val steve: Person = "Steve"
// Prints "Steve is happy"
println("$steve")
}

How to express in Kotlin "assign value exactly once on the first call"?

Looking for a natural Kotlin way to let startTime be initialized only in a particular place and exactly once.
The following naive implementation have two problems:
it is not thread safe
it does not express the fact "the variable was or will be assigned exactly once in the lifetime of an Item instance"
class Item {
var startTime: Instant?
fun start(){
if (startTime == null){
startTime = Instant.now()
}
// do stuff
}
}
I believe some kind of a delegate could be applicable here. In other words this code needs something similar to a lazy variable, but without initialization on first read, instead it happens only after explicit call of "touching" method. Maybe the Wrap calls could give an idea of possible implementation.
class Wrap<T>(
supp: () -> T
){
private var value: T? = null
private val lock = ReentrantLock()
fun get(){
return value
}
fun touch(){
lock.lock()
try{
if (value == null){
value = supp()
} else {
throw IllegalStateExecption("Duplicate init")
}
} finally{
lock.unlock()
}
}
}
How about combining AtomicReference.compareAndSet with a custom backing field?
You can use a private setter and make sure that the only place the class sets the value is from the start() method.
class Item(val value: Int) {
private val _startTime = AtomicReference(Instant.EPOCH)
var startTime: Instant?
get() = _startTime.get().takeIf { it != Instant.EPOCH }
private set(value) = check(_startTime.compareAndSet(Instant.EPOCH, value)) { "Duplicate set" }
fun start() {
startTime = Instant.now()
}
override fun toString() = "$value: $startTime"
}
fun main() = runBlocking {
val item1 = Item(1)
val item2 = Item(2)
println(Instant.now())
launch { println(item1); item1.start(); println(item1) }
launch { println(item1) }
delay(1000)
println(item2)
item2.start()
println(item2)
println(item2)
item2.start()
}
Example output:
2021-07-14T08:20:27.546821Z
1: null
1: 2021-07-14T08:20:27.607365Z
1: 2021-07-14T08:20:27.607365Z
2: null
2: 2021-07-14T08:20:28.584114Z
2: 2021-07-14T08:20:28.584114Z
Exception in thread "main" java.lang.IllegalStateException: Duplicate set
I think your Wrap class is a good starting point to implement this. I would definitely make it a property delegate and touch() could be much simplified:
fun touch() {
synchronized(this) {
check(value == null) { "Duplicate init" }
value = supp()
}
}
Then you can remove lock. But generally, this is a good approach.
If you would like to reuse lazy util from stdlib then you can do this by wrapping it with another object which does not read its value until asked:
class ManualLazy<T : Any>(private val lazy: Lazy<T>) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
return if (lazy.isInitialized()) lazy.value else null
}
fun touch() {
lazy.value
}
}
class Item {
private val _startTime = ManualLazy(lazy { Instant.now() })
val startTime: Instant? by _startTime
fun start(){
_startTime.touch()
}
}
Of course, depending on your needs you can implement it in a much different way, using a similar technique.
This may be considered exploiting or hacking lazy util. I agree and I think Wrap approach is a better one.

kotlin function default arguments from java

given following Kotlin class:
class Foo {
public fun bar(i: Int = 0): Int = 2 * i
}
How should I call 'bar' function without any parameter from a java/groovy code?
def f = new Foo()
f.bar() //throws: java.lang.IllegalArgumentException: Parameter specified as non-null contains null
You can do this now in Kotlin. For your class method, use the #JvmOverloads annotation.
class Foo {
#JvmOverloads public fun bar(name: String = "World"): String = "Hello $name!"
}
Now simply call it from Java:
Foo foo = new Foo();
System.out.println(foo.bar());
System.out.println(foo.bar("Frank"));
Outputs the following:
Hello World!
Hello Frank!
I'll post the real answer shortly, but if anyone is wanting to do this from reflection, here is how the code would look. Much more complicated, but educational about how to use Kotlin reflection for KCallable.
Here is the class to call:
class Foo {
public fun bar(name: String = "World"): String = "Hello $name!"
}
Then we need a utility class in Kotin that can receive an instance of a class, a method from java reflection, and the parameters by name. This only works with non-primitives:
class KReflectHelper {
companion object {
#Suppress("UNCHECKED_CAST")
#JvmStatic fun <T> callKotlinMethodWithNamedParms(instance: Any, method: Method, parmMap: Map<String, Any>): T {
val callable: KFunction<T> = method.kotlinFunction as? KFunction<T> ?: throw IllegalStateException("Method is not a Kotlin method")
val unusedParms = HashSet(parmMap.keys)
val callableParms = hashMapOf<KParameter, Any?>()
callable.parameters.map { parm ->
if (parm.kind == KParameter.Kind.INSTANCE) {
callableParms.put(parm, instance)
} else if (parm.kind == KParameter.Kind.VALUE && parmMap.contains(parm.name)) {
unusedParms.remove(parm.name)
callableParms.put(parm, parmMap.get(parm.name))
} else if (parm.kind == KParameter.Kind.VALUE) {
if (parm.isOptional) {
// default value will be used!
} else {
throw IllegalStateException("Missing required parameter ${parm.name}")
}
} else {
throw IllegalStateException("Cannot call methods that are not direct instance methods")
}
}
if (unusedParms.isNotEmpty()) {
throw IllegalStateException("Unrecognized parameters passed to function: $unusedParms")
}
return method.kotlinFunction?.callBy(callableParms) as T
}
}
}
Now that static method can be called from Java, but it isn't so much fun. A code generator would really be required. Calling it from Kotlin is much easier and some frameworks (such as Klutter and Kovert) already use something along these lines.
Foo foo = new Foo();
System.out.println(foo.bar("Frank"));
Method barMethod = Foo.class.getMethod("bar", String.class);
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("name", "David");
System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));
// now call using the default
parms.clear();
System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));
Ouput:
Hello Frank!
Hello David!
Hello World!