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

guard-else #1215

Closed
bbrk24 opened this issue May 4, 2024 · 4 comments · Fixed by #1228
Closed

guard-else #1215

bbrk24 opened this issue May 4, 2024 · 4 comments · Fixed by #1228
Labels
proposal Proposal or discussion about a significant language feature

Comments

@bbrk24
Copy link
Contributor

bbrk24 commented May 4, 2024

Now that we have isExit for other reasons, Swift-style guard seems implementable. At first glance, it seems identical to unless:

guard CONDITION else {
  STATEMENTS
}
// vvv
if (!CONDITION) {
  STATEMENTS
}

However, there are two key differences:

  1. If the condition creates any bindings (such as guard x? := getX() else { ... }), the bindings are only available outside the else block.
  2. STATEMENTS must be an "exit" of some sort, in order for 1 to be possible.

The primary use case is to prevent "pyramids of doom" when there are many bindings to be done:

if x? := getX()
  if y? := getY()
    if z? := getZ()
      setPoint x, y, z
// vvv
guard x? := getX() else return
guard y? := getY() else return
guard z? := getZ() else return
setPoint x, y, z
@bbrk24
Copy link
Contributor Author

bbrk24 commented May 4, 2024

Supersedes #756 I suppose

@STRd6
Copy link
Contributor

STRd6 commented May 4, 2024

A couple thoughts:

I'm reluctant to add any more reserved words like guard. Would unless x? := getX() else return be an acceptable spelling of this feature?

Maybe upgrading pipes to better handle piping to return/throw and allowing something similar to declaration conditions could help with this. #897 (comment)

x := getX() !> return
---
let ref = getX(); if(!ref) return ref; const x = ref;

Possible conditional pipe options: ?>, !>, ?|>, !|> maybe something else?

@bbrk24
Copy link
Contributor Author

bbrk24 commented May 4, 2024

unless-else reads like a double-negative, but otherwise I'd be fine with it.

@edemaine
Copy link
Collaborator

edemaine commented May 4, 2024

Pipe conditions do seem like a reasonable possible approach. We might need one for truthy and one for nonnull. We've talked about ?|> before to act like "if nonnull, then pipe into rhs".

Given how much guard resembles unless, I'd be tempted to spell it like so:

unless x? := getX()
  throw new Error "Missing x coordinate"
unless y? := getY() then return
unless z? := getZ() then return
setPoint x, y, z

#756 points out that our current meaning of unless x := ... isn't very helpful; it just exposes a falsey value for x inside the block. The proposed alternative would be to expose the declaration outside the unless block instead — essentially opposite of if, which kind of makes sense?

Alternatively, we could pull the declaration outside:

x := getX() ?? throw new Error "Missing x coordinate"
y := getY() ?? return
z := getZ() ?? return
setPoint x, y, z

This works for throw, but not for return, because we don't yet have a way to expressionize return. When it's at the top level of a declaration like this, I imagine we could handle it though.

@edemaine edemaine added the proposal Proposal or discussion about a significant language feature label May 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal Proposal or discussion about a significant language feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants