Johan
Johan

Reputation: 40520

Create instance in Kotlin and only set property if not null

I have a data class that looks like this:

data class MyDataCass(val x: String, val y: String, 
                      val something: Something = Something(),
                      val somethingElse : SomethingElse = SomethingElse())

Since this class is going to be used from both Kotlin and Java I've also created a builder to make it easier to construct it from Java. The problem is that something and somethingElse are optional and I'd like to avoid duplication of the default values. This is essentially what I've tried:

data class MyDataCass(val x: String, val y: String, 
                      val something: Something = Something(), 
                      val somethingElse : SomethingElse = SomethingElse()) {

    class Builder() {
        private lateinit var x: String
        private lateinit var y: String
        private var something: Something? = null
        private var somethingElse: SomethingElse? = null

        // builder functions to set the properties defined above
        ...

        fun build() = MyDataCass(x, y, something = ??, somethingElse = ??)
    }
}

What I'd like to do is to set something and somethingElse only if they've been defined by the builder (i.e. they are not null), otherwise I'd like to use the default values as defined by the data class constructor. I could of course change the build function to look like this:

fun build() = if (something == null && somethingElse == null) {
        MyDataCass(x, y)
    } else if(somethingElse == null) {
        MyDataCass(x, y, something = something)
    } else {
        MyDataClass(x,y, somethingElse = somethingElse)
    }
}

but I find this to be quite verbose and error prone. Is there a less verbose or more idiomatic way of achieving this?

Upvotes: 4

Views: 2324

Answers (1)

zsmb13
zsmb13

Reputation: 89578

This is not supported very well by the language, if there was a good solution to this question that would help you too.

With that said, here's what I could come up with that lets you have the default values declared just once - at the cost of duplicating other code, however:

data class MyDataCass(val x: String, val y: String,
                      val something: Something,
                      val somethingElse: SomethingElse) {

    companion object {
        operator fun invoke(x: String, y: String,
                            something: Something? = null,
                            somethingElse: SomethingElse? = null) =
                MyDataCass(x, y,
                        something ?: Something(),
                        somethingElse ?: SomethingElse())
    }

    class Builder {
        private lateinit var x: String
        private lateinit var y: String
        private var something: Something? = null
        private var somethingElse: SomethingElse? = null

        // builder functions to set the properties defined above
        // ...

        fun build() = MyDataCass(x, y, something, somethingElse)
    }
}

This way you can keep using the builder from Java, and in Kotlin the syntax that looks like is a call to the constructor is instead a call to the invoke function of the companion object, which has the default values. Your data class of course still has non-nullable types so that it's easier to use.

Upvotes: 3

Related Questions