data class DeviceResponse<T>(val status: ConnectionStatus,val data:T?,val errorMessage:String?)
ConnectionStatus can be SUCCESS, UNKNOWN_FAILURE, ATTACHMENT_NOT_MOUNTED,…etc
in case of success the data is non-null and errorMessage is null
in case of failureerrorMessage is non-null and data is null
[values - data, errorMessage are depending on the connectionStatus value]
is there any way I can tell this to the compiler and compiler can do a smartcast and also impose a restriction.
or any better approach of doing this?
Thanks in advance.
val result = getResultContainer() // made up class for example
result.assertSuccess() // smart casts the type on rerurn
// Or maybe
if (result.isSuccess()) { ... } // Smart casts type on true (and false)
On mobile so I can’t write out a runnable example atm. The main point is contracts can allow for telling the compiler which subtype you have and information about nullability.
New to contracts. So I have to create function isSuccess() that tells the compiler about nullability of data and errorMessage fields.
but I cannot reference field names in contract right? (I’ve read this from a blog post.)
So how do I apply the contract.
contract{
return(true) implies result.data!=null && result.status = SUCCESS
}
Maybe I’m missing something but what you want is not really possible with contracts right now. I don’t think contracts will let you get out of using a sealed class.
The best you can do is add an extension method for DeviceResponse that works just like a type check, so instead of writing result is Success you could call result.isSuccess() and have it smartcast.
However result.assertSuccess() is a nice idea. I think it would look something like this
fun DeviceResponse.assertSuccess() {
contract {
return implies this is SuccessDeviceResponse
}
if (this !is SuccessDeviceResponse) error()
}
However if the restrictions on contracts haven’t changed (I’m still on 1.4) it has to be an extension function and you would still need the sealed class structure.
Yeah, contracts are probably not the best solution in this case. My intention was to make sure someone mentioned it
Contracts might be valuable is if you want to do more complex work that a simple instance check can’t do. For example; if you had multiple parameters that influenced the result. Or if you allowed “unsuccessful” instances of a Success class (and some fancy visibility restrictions), or any case where instance checks don’t tell the whole story and the cast is only one of multiple effects of the function.