Bikeshed: A consise verb for the `?` operator

I don’t like throw or rethrow because then the proposed block construct would have to be called catch (you catch what is thrown).

The problem is that catch is already used for panicking in catch_unwind, and confounding panics with impl Try values will only lead to unnecessary confusion.

Instead of throwing and catching I think we should try to find another set of terms to represent the error propagation and the block which represents the fallible action/attempt.

7 Likes

Instead of try or catch we could find another name for the block construct.

Consider this: a fn and a closure are both perfectly capable of capturing the errors from ? without requiring any special keyword. The block construct could have a name that makes you think more of a code routine with a (return) value. Perhaps proc? It’s already a reserved keyword. (hasn’t been used since 2014)

Now, the ? operator can have any name not tainted by exception handling.

  • soft unwrap — like .unwrap(), but without panic
  • error return — I like something with return in it. Knowing that ? expands to match { Err => return } helps understand it. That knowledge could be compressed in the name itself.
1 Like

Now, the ? operator can have any name not tainted by exception handling.

fault operator? quit operator? live fast die young operator?

1 Like

return if

reterr (short for return error)

retfail

exiterr

conditional break

conditional exit

bump

explode

push (“Explicit Exception Propagation Operator”)

1 Like

I’m all-in for “try”: there doesn’t seem to be much downside, and it captures the intent “try to get this value”.

It’s not general exception handling, because Result::Err is not an “exceptional” case. Result is a data type like anything else, and ? is fundamentally unpacking that data type- not re-throwing an exceptional error. It’s trying to get the contents of something, and early-returning otherwise.

6 Likes

I’m all for that. ? stays the 'try' operator, and marks expressions that might produce errors; catch limits error propagation. People coming to the language will see that it's idiosyncratic, but will have a correct intuition about what each piece does. Yes, catch is syntactically different than it is in other languages, but that's because it's invariant and doesn't require any handlers, so you can just catch the block rather than having a block and putting catch as a postfix operation.

catch_unwind is a library function and doesn't present a real learnability hazard. People will generally encounter it long after try/catch and know that catching panic unwinding is a distinct operation by that point. The distinction is in the name.

The parallels to exception handling in other languages are actually fairly apt and thus will help people learn how to use it, so the feature isn't tainted by them.

This also suggests it should stop a return, which is unfortunate. You can already just use an immediately-invoked function if that's what you want. do could work, but it's so general of a term that it's not really suggestive of the intended use. It would probably work better as a way to evaluate more general reified control flow. block would be a bit on the nose, and doesn't distinguish from the normal blocks that already exist in the language. However you have to write it, people know what a catch operation does. Even if we went with try blocks, people would still probably grasp what the intended behaviour is. You can't get that if you invent new terminology.

Anyways, 'maybe' is actually growing on me, though I'm still concerned about it increasing confusion with option-chaining. I've noticed that I call ?Sized "maybe sized".

3 Likes

bubble because it bubbles errors. I also thought bail was a decent choice, but sounds a little scary. At least bubble has a very friendly rainbows-and-unicorns feel.

20 Likes

Bubble does sound nice. It has the same meaning as propagate but it is shorter, shinier, and simpler.

5 Likes

? does one of the two actions:

  • the likely path, it try read/unwrap the ‘success value’ a function returns;
  • the unlikely path (if the try fails), it returns/propagates the ‘error value’.

I can’t provide a full description in a few short words.

Perhaps… the try operator is still the best, which should not be changed.

Bubble is the first word for this proposed that I’ve liked! +10 for Bubble!

1 Like
  • eh (the Canadian version)
  • hope (because it is for the most part concerned with the happy path)

Edit: For real, though, I like bubble very much.

1 Like

:+1::smiley: This is a great choice: it's succinct and expresses the equivocation inherent in the operator.

Re „rethrow", since the etymology of that word is „repeat throw", doesn't that imply the pre-existence of „throw"?

1 Like

As a Canadian I would love for it to be called the eh operator but bubble makes more sense

2 Likes

@scottmcm As another Canadian, what do you say aboat “eh?”, eh?

2 Likes

So the action would be “to bubble”? Or would you “Pop the bubble”? :wink:

How about the, “Bubbles” Operator? Because, you know, unlike Corey & Trevor, who always fail, “Bubbles” usually “gets it done”, but, he’ll report back if he can’t reliably get the job done. So, the “Bubbles” operator bubbles up failures, but, usually just gets the job done (unlike Corey & Trevor).

This also has the magnanimous feature of tying back to Canada, eh? Then, when things fail we can, “Blame Canada! Blame Canada!”

Another possibility:

VOMIT

Because, the ? operator “throws up and returns” any error (bad stuff) to the caller. So, it could be the “vomit operator”. You could say things like, “I called foo with bar and it vomited Error(baz)!”.

If that’s too harsh, how about, one of these:

  • hurl (nice because a synonym for both “throw” and “vomit”)
  • expel
  • eject

I kinda like, “hurl”! (But, I’m still partial to “Bubbles” (not “Bubble”)). It’s the “Bubbles Operator”, It’s the “Vomit Operator”, It’s the “Hurl Operator”.

“Hurl” or “Bubbles” definitely!

“Hurl” works nice with “Catch”.

let x = catch {
    SomethingFallible()?;
    ...
}

Explanation would be:

If something fallible hurls an error I’ll catch it and assign it to x; otherwise, I’ll assign to x whatever the final result of the block is.

-or-

If something fallible bubbles and error I’ll catch it and assign it to x; otherwise, I’ll assign to x whatever the final result of the block is.

When coupled with “catch”, “hurl” works better than “bubbles”, but, I still like “bubbles” a lot.

Argument for “eject”:

“Eject Operator” works good because it invites the vision of ejecting from an aircraft when something goes wrong. It is different from “throw/try” (in exception-based language) so having a different name that still evokes the right kind of mental model is good. Also, “eject” would work good with the idea of “catch” blocks, but, in this case calling them “land” blocks might be better:

let x = land {
   somethingFallible()?;
   ...
   rv
}

Explanation:

If something fallible ejects and error, from the “Eject Operator” (?), then I’ll land the error and assign it to x; otherwise, I’ll just land the final result of the block and assign it to x.

fn Foo() -> Result<T,E> {

    ...
    let t : T = SomethingFallible()?;
    t
}

Explanation:

Function foo will return a Result<T,E>. When it calls something fallible, if something fallible returns an error, the “Eject Operator” will eject the Error as the return value of Foo; otherise, the non-error return value will be returned.

I think the above sort of language gives the right mental models without using the same language (try/throw/catch) as exception-based languages, but, clearly conveys that the ideas are similar, but, different.

2 Likes