Bikeshed: Rename `catch` blocks to `fallible` blocks

The Try trait is unstable <https://doc.rust-lang.org/nightly/std/ops/trait.Try.html>, and has not been proposed for stabilization -- on the contrary, the recent discussion on its tracking issue is about dissatisfaction with the current design:

2 Likes

Well, that sort of changes my opinion then. I, for some reason, thought that Try had recently been stabilized. If it hasn't, then I would say that whatever we agree is the appropriate keyword for these "fallible" blocks should be the same name that the "Try" trait should have. If "Try" is pretty much a given for the "Try" trait, then probably just use "try" for the fallible block. If the "Try" trait is still open to renaming, then, I think the community should agree on the appropriate name for both the block and the trait. Again, I like:

  • fallible / Fallible
  • errable / Errable
  • unsure / Unsure
  • resultof / ResultOf
  • uncertain / Uncertain
  • erring / Erring

I'm not sure how I feel about all of the above, but, they all seem better than "Try". I've ordered them above in what I would prefer from most preferred to least preferred (I think). Anyone else think anything like this might be a way forward on this discussion?

Another name possibility is maybe {} / trait Maybe.

3 Likes

I like it!

Though, if memory serves correctly, Maybe is the monad in Haskell that is akin to Option in Rust, is it not? So, maybe (see what I did there) Maybe might not be the right thing either.

IIUC, Option and Result are both monoids. Would that make ? a monoid operator and Try a monoid trait? :smiley: I could live with maybe, as eventually the puns would be delivered deadpan. :wink:

More things using the try_ prefix were FCP'd for stabilization (try_from, try_fold, etc). But that's just continuing the pattern of marking fallible things with that prefix, like Mutex::try_lock.

1 Like

Yes it is (and i saw what yo did here :smiley: ). And i see your problems with using "already" established names for "things" that would impose other semantics in Rust by using it. But i also lean to the sentiment of "It does not matter as long as it leads the user into the right direction although its not a correct substitute in detail".

Your argument against catch is, that it is used in other languages in the context of exceptions with a different semantic. But it is within the domain of error handling. So being opposed to every term that was ever used elsewhere which has a different semantic is very limiting and also not exhaustive (nobody knows every occurrences etc. and where do we draw the line between popular/unpopular if we decide to reuse unpopular ones) which could be a worse trade off of reusing an established term but with a different semantic but within a certain domain. You see, you liked maybe (i do too) but are limiting yourself to not like it because Haskell is using it in a different way semantically. The question here is at which point it does not really matter? try, catch, maybe (to choose some) are good candidates and to be honest i have no problem with catch because even though it is used in many other languages for a different thing semantically it is easy for most of the programmers out there to associate this term with error handling – and that might be enough to reduce mental overload. If i see catch { .. } with a minimal example i claim that more beginners understand AND remember what this means and how to use it opposed to a term like trap etc. which they never saw in any other programming language and their brain is not wired to that term belonging to the domain of error handling. I imagine people sitting in front of the monitor wondering "what was this weird keyword again to stop propagating errors .... lets consult documentation"

TLDR; I see your problem with reusing terminology in semantically different contexts BUT i think it is unnecessarily increasing mental overhead to use terminology not very popular in current programming languages! And i hope your struggle with maybe (which might be a good candidate) is self evident here?

6 Likes

There’s a bunch of stable functions with try_ prefix already, so I think in Rust’s context it already has an established meaning. Change to a different keyword not related to try/catch would have to deal with the dilemma of either duplicating these functions for consistency or still having try/catch-related names and naming inconsistency.

5 Likes

Whether similar-but-not-quite-same features should have same or different names is context dependent:

  • “traits are like Java interfaces” is actually a very helpful explanation to novices who try (and fail) to do OOP in Rust. Even though traits in some ways aren’t like interfaces, it sets close-enough frame of mind to get started.
  • Rust’s enum is different from C’s enum, but it doesn’t cause confusion.
  • “References” on the other hand are suuuper confusing to C++ programmers who expect them to be usable like regular pointers. I’d prefer &/&mut to be called something completely different, like “read permission”/“exclusive read/write permission”.
3 Likes

A heads up: I’m currently in the process of writing an RFC for the keyword reservation of keyword { .. } block expressions. I will probably be done with it today.

Interesting. At the risk of creating a tangent, I'm usually biased toward the C++ model of programming reality, and I always found "references" to be an extremely intuitive and broadly accurate term. To me the biggest difference between C++ references and Rust references is simply that Rust tries a lot harder to provide some basic semantic guarantees for them, e.g. that they even have a referent so it's safe to dereference them.

(Not that this affects your general point that "Whether similar-but-not-quite-same features should have same or different names is context dependent." Of course I agree with that)

2 Likes

To me using unknown keyword would be confusing. if, enum, and for does not operate the same way in Rust than in most languages I know, but I am happy they where not renamed because their intent is pretty much the same.

Likewise the intent of try block is pretty much the same than in languages with exception. As a beginner, faillible, maybe or trap, would have been puzzling for me. Using Result values instead of exception is a technical detail I will have to learn anyway as soon as I will need to use them.

12 Likes

The RFC is now published: https://github.com/rust-lang/rfcs/pull/2388

1 Like

Just as an apparent minority in this thread, I’d like to voice my support of the catch keyword.

My only confusion with these blocks was never what they do, but only why one would use them. My thinking roughly was: “If catch { func()? } is the same as func(), why would I even need these blocks?” This type of confusion, i think, is best addressed by documentation.

Regarding confusion with exception-based error handling, I think the chances are rather slim for one simple reason: The syntax is different. The catch clause in languages using exceptions always require an exception type to be specified, whereas the Rust catch block needs no further annotation:

// C++
try {
    // ...
} catch (std::runtime_error&) {
    // ...
}
// Rust
let x = catch {
    // ...
};

I also don’t share the sentiment that the meaning of catch blocks were unintuitive for people not having a background in exceptions. I interpret this block as “catch any errors that might occur in this block and continue after it”, which seems rather straight-forward to me.

In summary, I think that catch catches* the meaning of the block rather well and that fears of confusion with constructs from exception-based error handling are not unfounded, but disproportional. Most of the alternatives suggested in this thread are also okay, but their novelty might be off-putting to new learners of Rust. Among them, I think I’d prefer try, fallible, and trap the most. (resultof seems too unrelated to error handling at all.)


* pun intended

7 Likes

I though about a view criteria for choosing a word:

  1. Whatever name is chosen it should be a simple english word which we can be sure people with a less solid english foundation know
  2. it should not collide with words used in rust in different contexts
  3. it should be similar to what other languages use for error handling (including exception error handling)
  4. it is probably a good idea if it is not exactly the same as what other languages use for exceptions
  5. it is probably a good idea if it is not associated with a specific error type implementation/schema
  6. if there are two words with extremely similar meaning and usage it is probably preferable to use the simpler and/or shorter word

(to continue)

1 Like

Based on this criteria I think only trap and catch are left because:

  • try:

    • + on intuitive understanding (similar to other languages)
    • big - on intuitive understanding (to similar to other languages, it’s likely users would expect a catch block, and wonder why it doesn’t handle panics)
  • fallible:

    • + on not overlapping with exception handling terminology
    • big - as it’s derived from Failure which currently is kinda coined as a specific kind of error type which is static and has a backtrace (Failure crate). Also even without the failure crate I would use failure as a word for a more serve error, through maybe I’m alone with this?
    • - due being long and easy to confuse in it’s spelling (falible, failible faillible ?? ), this might sound off-topic but for anyone which has trouble with spelling and isn’t a native english speaker this is a (potentially) big think
  • catch:

    • + on intuitivity (similar to other languages)
    • at the same time different enough to be less likely to be confused, so no - here
  • trap:

    • very small + on intuitivity, trapping errors is used in some context (mainly where errors are signaled). It’s also a word similar to catch.
    • + on not overlapping with exception handling terminology
    • small - on overlapping with signal handling and in extension of this hardware exceptions, but I think as rust works at a different abstraction level this should be fine.
  • resultof

    • + for explaining what it does (you get the result of the following blog)
    • small - for being more than one word
    • small - for not being in the rust naming schemes (which would be result_of or ResultOf, which in turn would get be big - for looking like a function/type but definitely not like a keyword)
  • [EDIT] maybe:

    • - on not being intuitive at all, catch-block does give you the result of the following block of code, not maybe a result, Through you could say it maybe gives you an error or maybe an item and merges this into a singe result returned. (I personally would guess maybe is an alternate form of an option, or that it maybe executes the following block on code depending on some context).
    • + on not overlapping with exception terminology

Personally I think I would go with catch or trap, basing the decision on how much I want to distance it from traditional exception handling.

And I thinks both failible and try are a bad idea.

2 Likes

You mention try may be confusing that it doesn’t catch panic!(), but I come to the opposite conclusion:

  • try {} blocks are similar to try_ functions: try { foo() }try_foo(). The existing try terminology in Rust is not related to panics at all, but already has plenty of uses related to result wrapping

  • There is already panic::catch_unwind(|| {}), so “catching” in Rust already refers to panics. It wouldn’t be unreasonable to think that catch {} is a syntax sugar for panic::catch_unwind(|| {}).

17 Likes

I just thought of another possible color for the bikeshed: Perl-style.

let x = eval {
    this()?;
    that()?;
    theother()
}
2 Likes

I'm thinking the same thing. From Bikeshed: A consise verb for the `?` operator - #56 by illustrious-you :

let _: Result<Foo, Bar> = eval { // like "evaluation"
    foo()?;         // try operator
    fail Bar(0);    // break w/ err-wrapping, replaces throw
    pass Foo(0);    // break w/ ok-wrapping
    Foo(0)          // implicit Ok-wrapping
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.