I'm implementing vars in Kotlin that could receive out-of-bounds input from certain of their users. I'd like to be able to optionally call (only on input from these untrusted users) a validating constructor that can return null, and then use the Elvis operator to specify defaults in the case of invalid input, as in: var myFoo = Foo.fromInt(i) ?: 1. I'm currently using a companion object method to validate the input:
open class Foo(val x:Int) { // relies on valid x in 1..3
companion object {
fun fromInt(x: Int): Foo? = if (x in 1..3) Foo(x) else null
}
}
class Bar(x:Int) : Foo(x)
fun main(args:Array<String>) {
println(Foo.fromInt(2)) // Foo(2)
println(Foo.fromInt(20)) // null
// println(Bar.fromInt(2))
// would like Bar(2) but as expected, companion isn't inherited
}
When I subclass Foo, I know I have to recreate the companion object. I've tried inheriting the companion from an abstract class; however, the call to Foo(x) still points to Foo and not Bar, unless I override fromInt in each subclass' companion. Is there a better or more Kotlin-idomatic way to deal with this kind of pattern of a validating constructor that can return null rather than creating the requested object?
You can use the init block as well as require.
open class Foo(val x:Int) {
init {
require(x in 1..3) {
"relies on valid x in 1..3"
}
}
}
class Bar(x:Int) : Foo(x)
Example run:
>>> open class Foo(val x:Int) {
... init {
... require(x in 1..3) {
... "relies on valid x in 1..3"
... }
... }
... }
>>> class Bar(x:Int) : Foo(x)
>>> val b = Bar(3)
>>> val b = Bar(4)
java.lang.IllegalArgumentException: relies on valid x in 1..3
at Line_18$Foo.<init>(Line_18.kts:3)
at Line_19$Bar.<init>(Line_19.kts:1)
>>> b.x
res22: kotlin.Int = 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With