-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Proposal: add safe navigation operator #2816
Comments
For historical reference see #1095 and #1023 That thread also talked briefly about an operator for unwrapping error unions such as
It should be noted negatives to overloading
|
I suggest that the question mark and exclamation mark were to be placed before the dot, like |
Can you link to examples in the standard library that would benefit from this change? As mentioned in #1023, all control flow now uses keywords instead of sigils, which lines up with Zig's philosophies and would be nice to uphold. Perhaps it would look weird here, I dunno. For example, if we use a hypothetical keyword if (root_node.nodes then[0] then.symbol then.val) |val| {
return val;
} Most examples on the Wikipedia page use your suggested syntax, but the Crystal example uses a keyword. |
I don't know that stdlib is where this pattern would occur the most, but I do know it occurs a lot in data-driven application code e.g. server backend, games... I encountered it in my admittedly very-wip-and-maybe-should-be-totally-refactored Deflate implementation Huffman code tree attempt, which is where the "real example" above is from. I would remind of the following points:
|
I agree with all of your points @nodefish , I'm just confused by the value of |
You are right, |
Fact! I don't think anyone is arguing otherwise. :)
As @Hejsil has pointed out, the current
Hyperbole aside, my counteroffer wasn't meant to increase explicitness, it was meant to preserve the practice of only offering keywords for control flow. Since this proposal adds sugar to control flow, I thought it should be mentioned. (Note that the existing |
I would much prefer not overloading |
These are some forms that came to mind: Anonymous chained unwraps with
Named chained unwraps with the
Labeled chained conditions - something like the chained unwraps, but with nicer left-to-right reading.
Short-circuit-if-null, or something like that? The
|
@raulgrell your examples there are much too verbose for my liking. Perhaps they could be refined. |
@SamTebbs33 I agree, but it was the best I could do in a way that I felt is consistent with the rest of the language. The anonymous chained unwraps with
The named chained unwraps with : separator would be better if parentheses weren't required in if statements, but we don't have a solution for that...
The issue with the labeled chained conditions is that the label becomes a source of data as opposed to a destination. This looks better, but is a bit inconsistent with other uses of labels. You could also also consider The last one, Short-circuit-if-null, is no more verbose than the proposed replacement of
Another variation on the named chained unwraps would be:
All of these are inconsistent with the "control flow with keywords" principle that Zig adheres to and are thus flawed. I also think we can't have operators that are both infix and postfix for parsing reasons, so that "syntax 1" variation probably out as well... It's a doozy =P |
This issue is to propose the addition of the safe navigation operator.
Currently, working with chained optionals causes a lot of friction, because a null check/unwrap must be done at each level of indirection, resulting in code that is both harder to write and read.
Real example:
const result = if (root_node.nodes) |nodes| if (nodes[0].symbol) |sym| sym.val else null else null;
(only 2 levels of indirection, and it's already on the verge of losing clarity - suffice to say this scales very poorly for n>2 chained optionals).When an
else
branch is needed for the situation where any of the chained fields is null, things can even get significantly worse, e.g.:This is an especially significant problem in zig compared to some other languages, because null checks/unwraps cannot be combined in a single expression for safety reasons.
Proposed solution:
Add the safe navigation operator, such that any chained variable/field with this operator causes the whole expression (entire chain) to evaluate to null if it is null.
Syntax option 1:
varname?
The hyperbolic example becomes much clearer:
Syntax option 2:
In an IRC discussion about this proposed feature, some people expressed a preference for
.?
syntax on the basis of consistency with.*
; e.g.varname.?
Consequences
In both options, the current
.?
should be deprecated (in order to reduce ambiguity for option 1, and by necessity for option 2). The proposed feature makes it easy to replace this functionality e.g.article?.author?.name orelse unreachable
-- which, it can be argued, is superior than using a shorthand, sinceunreachable
should never be reached at runtime (more explicit).Additional ideas
mikdusan
proposes further unwrapping operators in the same vein, particularly the dereferencing operator.*
being used to replace.?
(general unwrap/"unbox" operator).Additionally, a similar error unwrapping operator could perform the same function for chained members that might evaluate to an error, resulting in the entire chain evaluating to the first error encountered.
Thank you for discussing this with me on IRC: samtebbs, mikdusan, Flaminator, scientes, mq32, fengb
edit: minor corrections
The text was updated successfully, but these errors were encountered: