How to use custom setter in Kotlin class constructor body


#1

Hello awesome community!
I posted the following question on SO but I think this is a better place to ask.

I couldn’t find a better title for describing how can I avoid code duplication (require expressions) in this Kotlin class:

class Person(email: String) {
    var email: String = email
    set(value) {
        require(value.trim().isNotEmpty(), { "The email cannot be blank" })
        field = value
    }

    init {
        require(email.trim().isNotEmpty(), { "The email cannot be blank" })
    }
}

#2

This could work:

class Person(email: String) {
    var email: String = email.required()
    set(value) {
        field = value.required()
    }

    private fun String.required() = this.also {
        require(it.trim().isNotEmpty()) {
            "The email cannot be blank"
        }
    }
}

#3

Yes! It works as expected. Anyway, you can imagine that an Entity may have several properties that would require some sort of validation.
Do you think that the following would be idiomatic ?

class Employee(age: Int, email: String, phoneNumber: String, department: String, area: String) {

private fun Int.requiredAge() = this.also {...}
private fun String.requiredEmail() = this.also {...}
private fun String.requiredPhoneNumber() = this.also {...}
...

}


#4

No, because in that case it would still be duplicated code. If this is a pattern that you find yourself to be repeating regularly, than property delegation is probably a better choice.

Your fields would look like this:

var email: String by Required("The email cannot be blank")

You would need to implement the Required delegation. See for example https://kotlinlang.org/docs/reference/delegated-properties.html

Note also that there might be an implementation of such a property delegation in the standard lib already. In that case you don’t need to implement it yourself.


#5

Thank you @fatjoe79 for the quick response. Code duplication is not something that I must get around although it is important. My main concern is how people in this community model domain entities (as in DDD) with this kind of validations. eg: a string not being empty, an int that should be positive, a flag that must be true for some reason, etc.
This is, when callers try to pass in argument that are invalid.

How do you personally manage this ?


#6

Back in the java days I used this pattern:

this.i = requirePositive(i)

In kotlin I use

this.i = i.requirePositiv()

In both cases I define the method/function in a common place, so that I can reuse it anywhere. I also add an optional message argument.

However please note that we just recently started using kotlin in our team. I am hardly eligible for knowing Kotlin best practices and idioms. I would imagine that the Delegation is an idiomatic solution, though I haven’t used it myself yet.


#7

Having said that, the amount of developers that just recently started using Kotlin skyrocketed. There are soon much much more of us than veteran kotlin developers. :wink:

The traditional best practices will need to prove themselves now. Maybe the growing community will come up with new best practices and idioms.


#8

Thank you for the insights! Looking forward to seeing more newcomers having this kind of discussions! :slight_smile: