kotlinforandroid
06/25/2022, 3:20 PMclass FormField {
var hasError: Boolean by mutableStateOf(false)
var errorMessage: String? by mutableStateOf(null)
// errorMessage != null iff. hasError == true
}
I tried contracts but one cannot reference variables that are not part of the contract method. I can't reason about this@FormField.errorMessage
inside the implies boolean expression.Youssef Shoaib [MOD]
06/25/2022, 3:35 PMval hasError get()= errorMessage != null
Youssef Shoaib [MOD]
06/25/2022, 3:37 PMsealed class Error
Like this:
sealed class ErrorStatus {
object NoError: ErrorStatus
class Error(val message: String): ErrorStatus
}
kotlinforandroid
06/25/2022, 4:15 PMderivedStateOf
. But what if the evaluation is happening another way? For example
fun interface Transform<in T, out R> {
fun transform(value: T): R
}
class Value<T, R>(
initialValue: T,
transformer: Transformer<T, R>,
) {
var value: T
fun evaluate(): R {
val result = transformer.transform(value)
validateEvaluate(result)
return result
}
@ExperimentalContracts
private fun validateEvaluate(value: R): R {
contract {
returns() implies (value != null)
}
if (value == null) throw RuntimeException()
}
}
// Usage
class Test {
val value: Value<String?, Float?> = Value(
initialValue = "1.0",
transformer = { it?.toFloat() }
)
fun test() {
// At this point, even with a type of `Float?` the value can only be a `Float`.
val float: Float = value.evaluate()
}
}
I'd argue that the value inside of the test method can only be non-null since T is in and R is out exclusively. However, my IDE still wants me to use !!
.Youssef Shoaib [MOD]
06/25/2022, 7:57 PMimport kotlin.contracts.*
fun interface Transformer<in T, out R> {
fun transform(value: T): R
}
class Value<T, R>(
initialValue: T,
val transformer: Transformer<T, R>,
) {
var value: T = initialValue
fun evaluate(): R & Any {
val result = transformer.transform(value)
validateEvaluate(result)
return result
}
@OptIn(kotlin.contracts.ExperimentalContracts::class)
private fun validateEvaluate(value: R) {
contract {
returns() implies (value != null)
}
if (value == null) throw RuntimeException()
}
}
// Usage
class Test {
val value: Value<String?, Float?> = Value(
initialValue = "1.0",
transformer = { it?.toFloat() }
)
fun test() {
// At this point, even with a type of `Float?` the value can only be a `Float`.
val float: Float = value.evaluate()
}
}
kotlinforandroid
06/26/2022, 12:16 PMYoussef Shoaib [MOD]
06/26/2022, 12:22 PMclass Value<T, R: Any>(initialValue: T, val transformer: Transformer<T, R?>) {...}