-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Coalesce for mixed nothing/missing: bug and design issue #26927
Comments
Good catch about the Base.convert(::Type{Union{Missing, Nothing, T}}, x::Any) where {T} = convert(T, x) Regarding the behavior of |
The problem I have is that I would not like to have I agree that the situation that we mix Alternatively
|
There's nothing special about
I guess one possibility would be to introduce I've filed #26929 for the crash mentioned above. |
This is exactly my point. I am flexible to whatever choice is made - given it is properly documented 😄 (I agree that If we wanted to use R as a reference you have that I am pushing this so much now as for me this function is an important part of data science targeted ecosystem in base Julia so I would prefer to have a well thought of API here in Julia 1.0. |
To show a situation that bothers me this is a simplified situation I had today:
and now you cannot use My point is that for interactive use current |
I think coalesce should handle exactly one value specially; a different value requires a different function. |
@JeffBezanson So how about adding |
@vtjnash has proposed this patch: diff --git a/base/some.jl b/base/some.jl
index f75a493d91..6b9e1c84b6 100644
--- a/base/some.jl
+++ b/base/some.jl
@@ -64,8 +64,8 @@ function coalesce end
coalesce(x::Any) = x
coalesce(x::Some) = x.value
-coalesce(x::Nothing) = nothing
-coalesce(x::Missing) = missing
+coalesce(x::Nothing) = error("no default value")
+coalesce(x::Missing) = error("no default value") Basically, the idea is that |
Another proposal in addition:
That way if you have, just pure mixtures of either nothing/missing or a value, that'll work just
Additionally @omus had a proposal to have a version of |
add promotion rule for `Union{Nothing, Missing, T}` fixes the bug part of #26927
add promotion rule for `Union{Nothing, Missing, T}` fixes the bug part of #26927
add promotion rule for `Union{Nothing, Missing, T}` fixes the bug part of #26927
Throwing an error when the result would be |
I have two additional comments/questions:
|
The idea of my proposal is that the sentinel value is optional. That way if you have a bunch of functions |
@Keno: yes - I understand this. But my question is: does there exist a realistic use case, when you use |
This came up on the triage call, and I think the consensus was to create a separate function what takes an explicit predicate for this case instead. (Or just use |
With #27157, I've thought a bit more about how to handle the case where |
Yes, that is part of the design. The idea would be that the most common case is that function would return either a sentinel or a value guaranteed not to be either sentinel (e.g. Union{Missing, Int}). It would be odd for a function to return either sentinel or a value. If a function does that, I agree the behavior is confusing, but the though was to make things as simple as possible for cases where the user knows things to be unambiguous (i.e. not requiring a first argument for the most common cases). |
OK, got it. Basically we just need to add methods to handle cases where |
During triage, @JeffBezanson and I violently objected to coalesce(nothing, 1) === 1
coalesce(missing, 1) === 1
coalesce(nothing, missing) === missing
coalesce(missing, nothing) === missing We didn't come to a conclusion but there was significant support for separating the unwrapping behavior of identity_or_nothing(x) = rand(Bool) ? Some(x) : nothing
unwrap(coalesce(identity_or_nothing(x), Some(0))) |
The other approach that was discussed was to go back to having two separate generic function. One that unwraps |
To give a concrete example of the first-argument-as-sentinel problem, suppose both coalesce(f(), g(), 0) If |
I think the key is to first be clear about what domain the function operates on. Currently there are two issues there:
I think we should define two domains, and have a function for each:
If that proposal isn't appealing, I could also tolerate the following:
|
How about calling that |
This is exactly what I think is best from the very start. |
First let me report a bug:
But I have tracked it because I want to get back to #26661 and I have second thoughts about the fact that
coalesce
mixes handlingmissing
andSome
/nothing
. It would help me if I understood why (maybe e.g. @nalimilan could explain or give a reference to an earlier discussion - I could not find it unfortunately).The problem I have is that I feel that current
coalesce
is not very useful for handling missing values becausecoalesce(Some(missing), "replacement")
returnsmissing
, so e.g. this pattern to get rid of missings in a vector does not work (it worked in old Missings.jl package):coalesce.([Some(missing), "a", "b", missing], "replacement")
.My first reaction is to have separate function for
missing
and separate forSome/nothing
but maybe there is some good reason to mix it.The text was updated successfully, but these errors were encountered: