-
-
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
RFC: Convenience syntax to unwrap Nullables (à la Swift if let
)
#15174
Comments
I'll read this more carefully in a bit, but I completely agree that we should try to add some sugar for this use case. |
Instead of using a macro you can consider using Julia's do syntax. This could look as follows: nullable{T}(f, n::Nullable{T}, alt::T) = isnull(n) ? alt : f(get(n))
nullable(n, 0) do x
x+1
end The first argument of the function We could extend Julia's nullable{T}(f, alt, n::Nullable{T}) = isnull(n) ? alt() : f(get(n))
nullable(n) do x
x+1
else
0
end The main difference to the suggestion above is that one uses lambda expressions and existing syntax instead of a macro. |
@eschnett Yes, see my point 4. But it requires a small parsing change (which I think it would be justified). @JeffreySarnoff I don't think that can be made to work, at least not without making quite profound changes in many parts of Julia. Automatic unwrapping of |
I had something similar in mind with allowing map for Nullables (#9446), but the ability of actually specifying a |
After thinking about this more, I'm ok with it, but I don't know what others want to do with Nullables in the long run. A few counterpoints (which may just reflect me being confused):
On my end, I've come to think that the best way to deal with the verbosity of nullables is to provide DSL's in which lifting happens totally automatically. But implementing those may be impossible without formal return types or some small core of arrow types at the heart of Julia. So I've kind of given up on trying to make progress. |
There is one major difference between Regarding longer/shorter code: You can write e.g. If you want to wrap the result of the calculation back into a nullable, then you'd want to implement map(n) do x
x+1
end Or, of course, Or, with the recently proposed "vectorizing" syntax: (x->x+1).(n) I don't think this syntax is intuitive for nullables, though. |
I traded monads for arrows and chased them awhile; got bored and let go of that quiver. |
@johnmyleswhite Yeah, as @eschnett said, this syntax is only useful for more complex situations where you don't want to simply return a value, but to perform a different action (like raising an error, or computing an alternative result).
That's interesting, but I must admit I find the C# syntax presented there is much simpler to grasp than Scala's Taking again inspiration from Swift, the macro I posted below could/should be extended to support multiple/nested @unwrap if x, x.y, x.y.z
...
end which would expand to: if !isnull(x)
let x = get(x)
if !isnull(x.y)
let y = get(x.y)
... # Replace x.y with y in user code
end
end
end
end Would that suit your needs?
Yes, I know that's a tough issue...
@eschnett I think it's non-intuitive when combined anonymous functions. :-) |
Your proposal for multi-expression |
Why would it be hard? Sounds quite doable to me, though my macro skills are still quite limited... |
My experience with macros is that there's just a lot of cases to get right. For example, a mixed chain of nullables and non-nullables in |
Right, it will make things more complex, but a few conditions on types which would be optimized out by the compiler could work. |
Indeed. I think you should try to make this work and submit a PR, but my vote isn't sufficient for inclusion in Base. That said, I think it's a good start towards getting us some of the sugar we need. (And I also generically have a lot of Swift envy at this point, so I like copying stuff from Swift.) |
I'd like to get more opinions from core devs before spending time on the more complex solution. Also, the simple macro above is a good start to evaluate whether this kind of syntactic sugar is useful. |
There are two different cases, depending on what the result of the calculation should be:
Which of these cases do you want to address with a macro? The former is similar to In the first case, you also need to decide whether the calculation that runs in the non-null case is allowed to return null. |
@eschnett There isn't really a "result" in that syntax. The point isn't to apply an operation and return a value, it's to run code on the value wrapped in a |
@nalimilan In my classification, since the code can return "anything", that's case two. |
@nalimilan When I wrote "result", I meant result in the sense that (almost) all statements in Julia are actually expressions, and can produce a result, and you can assign it to a variable. That "result" might be The key distinction I'm trying to make is whether the outcome of the calculation should always be another nullable (as you'd expect with a This is -- in my mind -- my case 2 above. If you disagree, then that's because I described my case 2 badly (apologies), not because I'm thinking of something else. |
No worries. It's just that I haven't considered seriously the question of return values, as it's not the primary goal of this syntax. Actually, the macro above does not allow assigning its result to a variable, because julia> y = if true
1
end
julia> dump(y)
Void nothing This is quite weird, as the return value is indeed printed at the REP. Maybe a bug? |
Works on 0.4.3. Do you build after #15188? |
@KristofferC Ah, that was likely it. I haven't rebuilt yet. Let's get back to the design discussion then. :-) |
@StefanKarpinski @JeffBezanson What's your opinion on this kind of syntactic sugar? |
An alternative is to use
although for blocks don't return anything :( |
@hayd Sounds interesting, but AFAICT that would be quite verbose when chaining as in |
I also agree that some convenient way of dealing with this would be nice, though I dislike the particular proposed use of |
Seems stale since Nullable has moved out of Base. |
I'd like to discuss the opportunity and possible implementations of a syntax similar to Swift's
if let
. The idea is to offer a compact syntax to check whether aNullable
is null, performing an action on its value if it isn't (with an optional fallback if it is).This was mentioned recently on julia-users: https://groups.google.com/d/msg/julia-users/pgaw6VnBJ34/bBe2lJ1mAQAJ
I gave a try at writing a macro offering a similar feature in Julia, and as expected it can be made to work quite easily. There are a few issues to discuss, though:
Nullable
in a rigorous way is a major feature, and this seems to be a quite common opinion nowadays.@if let
cannot be used because of parsing issues. That's not a big deal IMO, as I'm not a fan of that naming choice. I've retained@unwrap if
, but we could find a better name (if
is required to allowelse
).let x=get(x)
(i.e. you access the value with the same name as theNullable
). I think this is clearer as there's no reason to need both variables in the same context, and it avoids prompting people to use artificially different names for the "same" thing.do
syntax to allow for anelse
part, which would be implemented by passing two functions toget
(one for when a value is present, one for when it isn't). The advantage is that it could be useful in other places: for example to allow working efficiently with dicts, with code to update a value if found, and code returning a default value (?= "get or set" operator #2108).So, here's the macro, and examples of how it can be used:
Cc: @johnmyleswhite
The text was updated successfully, but these errors were encountered: