Stylianos Gakis
10/17/2023, 5:23 PMeither {}
block, I wanted to instead of ensuring that something is not null, something like ensureNull
which doesn’t exist of course 😄
My use case was that I do this
val userError: Error? = response.userError
ensure(userError == null) {
ErrorMessage(userError!!.message) // not getting smart-cast to userError being non-null here in order to be able to access `message` without a `?` or a `!!`
}
There’s no smart-contract that ensure
can use to ensure not only that the condition is true if the function returns, but also that the condition is not true if the function goes inside the raise
block, correct?@OptIn(ExperimentalContracts::class)
public inline fun <Error, B : Any> Raise<Error>.ensureNull(value: B?, raise: B.() -> Error): B? {
contract {
callsInPlace(raise, InvocationKind.AT_MOST_ONCE)
returns() implies (value == null)
}
return if (value == null) value else raise(raise(value))
}
Where you can propagate the right non-null B
into the raise
block by changing the signature of it, but then you gotta use that B which comes as the received of the lambda, and don’t get the nice smart-casting.
Also you gotta add this new function, and place it in the right spot etc of course.
At that point, maybe my best and most easy to the eye approach is to just do
val userError: Error? = response.userError
if (userError != null) {
raise(ErrorMessage(userError.message))
}
And I’m good. I get the right casting inside the if lambda, and the right assumption after the lambda is over, that userError is in fact nullable there.Alejandro Serrano.Mena
10/18/2023, 8:27 AMensureNotNull
on top of ensure
ensureNull
, but given that it's not as commonly used as ensureNotNull
, we decided it would pollute the namespace more than help (but we're open to discussion about this if several people find this function useful)Stylianos Gakis
10/18/2023, 9:21 AMdata class Foo(
data: Bar?
userError: Baz?
)
And I want to short circuit if userError is not null, and then I also can do ensureNotNull on data
I'm not sure it's useful enough to pollute the API of arrow here, so I would not be one to suggest to add it, but I'm leaving my use case here just in case other people have their own opinions on it too.simon.vergauwen
10/18/2023, 11:08 AMensureNull
today too 😅
I think it's a different way of modelling, I think when we designed these APIs we expected. fun validate(str: String): Either<ParsingFailure, Unit>
but I'm encountering fun validate(str: String): ParsingFailure?
(returns null
if successfull).
So it's using null
as a success value, kind of unexpected 😅 Not sure if it's similar to your use-case @Stylianos Gakis but it sounds familiar.
It's also quite typical for a Java SDK to return data class Result(val success: Response?, val failure: Exception?)
as you've shown above.CLOVIS
10/18/2023, 11:12 AMensure(foo == null)
but I rarely do anything in the message more than printing it so I've never really felt the need for a dedicated functionsimon.vergauwen
10/18/2023, 11:13 AMensure(foo == null)
was sufficient, in my case I slightly refactored the code.Stylianos Gakis
10/18/2023, 11:13 AMensure(foo == null)
but I rarely do anything in the message more than printing it so I’ve never really felt the need for a dedicated function
Yes, but our error was a type, and then we did want to do userError.message
in the raise block, so we’d have to do userError!!.message
to make it compile in our case. Something like thatAlejandro Serrano.Mena
10/18/2023, 11:44 AMraise
to remove the !!
, it doesn't add so much noise...
val userError: Error? = response.userError
if (userError != null) { raise(ErrorMessage(userError.message)) }
Stylianos Gakis
10/18/2023, 11:49 AMsimon.vergauwen
10/18/2023, 11:55 AMStylianos Gakis
10/18/2023, 12:04 PMsimon.vergauwen
10/18/2023, 2:09 PMStylianos Gakis
10/18/2023, 2:11 PMsimon.vergauwen
10/18/2023, 2:13 PMAlejandro Serrano.Mena
10/18/2023, 4:04 PM