Skip to content
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

Increased precedence for 'try' over 'orelse' #5436

Closed
gpanders opened this issue May 25, 2020 · 1 comment
Closed

Increased precedence for 'try' over 'orelse' #5436

gpanders opened this issue May 25, 2020 · 1 comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@gpanders
Copy link
Contributor

Given the function signature

fn foo() !?u8 {
    return null;
}

The following does not work:

const x = try foo() orelse 42;

But gives the error

Semantic Analysis [545/974] ./precedence.zig:6:22: error: expected optional type, found '@TypeOf(foo).ReturnType.ErrorSet!?u8'
    const x = try foo() orelse 42;
                     ^
./precedence.zig:6:25: note: referenced here
    const x = try foo() orelse 42;

Instead, one must write

const x = (try foo()) orelse 42;

This is because the orelse operator has higher precedence than try.

This is related to but distinct from #114 and #2138 as it refers to precedence between two similar operators: try and orelse.

Personally, I find

try foo() orelse 42;

to be much more readable and natural than

(try foo()) orelse 42;

The former reads almost like an English sentence and naturally follows the much more common logical flow of "first handle the error case, then handle the null case".

In fact, the paradigm of catching an error before unwrapping an optional (i.e. the !? syntax) is much more common than the converse of unwrapping an optional before catching an error (i.e. the ?(anyerror!) syntax): the standard library has about 160 cases of the former while only containing 4 of the latter (from a quick grep of the Zig source code). It therefore seems to make sense to increase the precedence of try over orelse since this use case is more common.

A counterargument might be that the use of parentheses reduces any ambiguity about which operation comes first (try or orelse); however, there will rarely be ambiguity in the first place since the first pattern is overwhelmingly more common. In the instances that the second pattern is used, one can instead write

try (foo() orelse {  }})

In the more general case of catch vs orelse, it is not as clear:

foo() catch |err| return err orelse 42;

This actually compiles, but is more ambiguous. In this case, parentheses should indeed be encouraged:

(foo() catch |err| return err) orelse 42;
@Vexu Vexu added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label May 25, 2020
@Vexu Vexu added this to the 0.7.0 milestone May 25, 2020
@andrewrk
Copy link
Member

We have an accepted proposal for this already, which is to require parentheses to disambiguate: #114

People can disagree about whether they expect try or orelse to have higher precedence, but nobody can disagree on what this should do:

const x = (try foo()) orelse 42;

Even people who are reading zig code for the very first time in their lives will know what that does, and that's the reasoning behind #114.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

3 participants