This pull requests ensures that nullable types cannot be used when working with Option or Result. Additionally, since refactoring was necessary anyway, catchOption, catchOptionAsync, catchResult and catchResultAsync were simplified so that only the value for the Some option and, respectively, the one for the Ok option must be returned.
It can be argumented that using Option with nullable types defeats its purpose. None should be used instead of using Some wrapping null. By enforcing this constraint, a lot of bugs can be prevented.
Also, consider the NI typedef below:
typedef NI = int?
void fn(NI? a) {
final option = Option.from(a);
}
If a is null, then this could mean one of these things:
a is null because a NI object referencing null was passed (null at the NI level, not "directly" at the NI? level)
a is null because a NI? object referencing null was passed (null at the NI level)
a is null because null was explicitly passed
What Option values were expected and which ones were created?
In the first case, a Some(null) value would make sense here, given that a nullNI value was passed. A None value is created instead. This is because all was passed was null and it is not possible to distinguish between NI? and NI types in this case. Even though it is valid to manually create a Some(null) value.
None is expected and created
None is created, even though it may not be clear if a was meant to be null at the NI or NI? level.
At the Result/Ok level, having a non-nullable T (i.e. T extends Object) would bring only benefits. An Option<T> type should be defined instead of a nullable T?. No longer having to decide between Option<T> and nullable type T? will result in a much more uniform style.
It is fine for E to extend Object, because:
An instance of Null cannot be thrown anyway.
An Object must be thrown, which important for catchOption, catchOptionAsync, catchResult and catchResultAsync.
Null would not be a good candidate for Err's type anyway.
In conclusion, enforcing non-nullable types removes ambiguity and prevents bugs.
This pull requests ensures that nullable types cannot be used when working with
Option
orResult
. Additionally, since refactoring was necessary anyway,catchOption
,catchOptionAsync
,catchResult
andcatchResultAsync
were simplified so that only the value for theSome
option and, respectively, the one for theOk
option must be returned.It can be argumented that using
Option
with nullable types defeats its purpose.None
should be used instead of usingSome
wrappingnull
. By enforcing this constraint, a lot of bugs can be prevented.Also, consider the
NI
typedef below:If
a
is null, then this could mean one of these things:a
is null because aNI
object referencingnull
was passed (null at the NI level, not "directly" at the NI? level)a
is null because aNI?
object referencingnull
was passed (null at the NI level)a
is null because null was explicitly passedWhat
Option
values were expected and which ones were created?Some(null)
value would make sense here, given that anull
NI
value was passed. ANone
value is created instead. This is because all was passed wasnull
and it is not possible to distinguish betweenNI?
andNI
types in this case. Even though it is valid to manually create aSome(null)
value.None
is expected and createdNone
is created, even though it may not be clear if a was meant to be null at theNI
orNI?
level.At the
Result
/Ok
level, having a non-nullableT
(i.e.T extends Object
) would bring only benefits. AnOption<T>
type should be defined instead of a nullableT?
. No longer having to decide betweenOption<T>
and nullable typeT?
will result in a much more uniform style.It is fine for
E
to extendObject
, because:Null
cannot be thrown anyway.Object
must be thrown, which important forcatchOption
,catchOptionAsync
,catchResult
andcatchResultAsync
.Null
would not be a good candidate forErr
's type anyway.In conclusion, enforcing non-nullable types removes ambiguity and prevents bugs.