How to use custom setter in Kotlin class constructor body

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" })
    }
}

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 Likes

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 {...}
...

}

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.

3 Likes

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 ?

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.

2 Likes

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.

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