Hi folks, in case you need to create your own type...
# codereview
g
Hi folks, in case you need to create your own type with it's own conditions for example an
Int
that has range from x to y. Where would you implement the check for the condition? In the constructor or in a factory function or something else. thanks in advance for any answers !
Here is how i implemented:
Copy code
public value class RegistrationId(private val value: Int) : Comparable<RegistrationId> {
    init {
        require(REGISTRATION_ID_RANGE.contains(value)) {
            "The registration id is a number between 1 and 16380 but got: $value"
        }
    }

    override fun compareTo(other: RegistrationId): Int = value.compareTo(other.toInt())

    override fun toString(): String = value.toString()

    /**
     * Adds the other value to this value.
     *
     * @throws IllegalArgumentException if the resulted [RegistrationId] is out of bounds.
     */
    public operator fun plus(other: RegistrationId): RegistrationId = RegistrationId(value.plus(other.value))

    /**
     * Adds the other value to this value.
     *
     * @throws IllegalArgumentException if the resulted [RegistrationId] is out of bounds.
     */
    public operator fun plus(other: Int): RegistrationId = RegistrationId(value.plus(other))

    /**
     * Subtracts the other value from this value.
     *
     * @throws IllegalArgumentException if the resulted [RegistrationId] is negative.
     */
    public operator fun minus(other: RegistrationId): RegistrationId = RegistrationId(value.minus(other.value))

    /** Converts this [RegistrationId] value to [Int].*/
    public fun toInt(): Int = value

    public companion object {
        private const val MIN_VALUE: Int = 1
        private const val MAX_VALUE: Int = 16380

        /**
         * A constant holding the [range][IntRange] an instance of [RegistrationId] can have.
         */
        @JvmField
        public val REGISTRATION_ID_RANGE: IntRange = IntRange(MIN_VALUE, MAX_VALUE)
    }
}
Would you say is preferable to create a factory function for this, to avoid throwing in constructor?
k
I think it's fine to throw in the constructor in this case. However, I would avoid repeating the number 16380, and instead make use of the IntRange toString:
Copy code
init {
        require(value in REGISTRATION_ID_RANGE) {
            "The registration id must be in the range $REGISTRATION_ID_RANGE but got: $value"
        }
    }
Also, I'm sceptical about your definitions of
plus
and
minus
. Does it really make sense to be able to add or subtract IDs?
g
Yes indeed,
plus
and
minus
have no value.
g
have you considered using a contract to enforce that int values passed in this object as within the specified range?
what you are looking for are called refinement types and there is this library that could help you get what you want https://github.com/ustits/krefty