From b9aca54cca01ed661b22722846604c3874fbcbe6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Apr 2018 20:15:16 +0200 Subject: [PATCH 01/11] rfc, try-expr: initial version. --- text/0000-try-expr.md | 834 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 834 insertions(+) create mode 100644 text/0000-try-expr.md diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md new file mode 100644 index 00000000000..b306be66650 --- /dev/null +++ b/text/0000-try-expr.md @@ -0,0 +1,834 @@ +- Feature Name: `try_expr` +- Start Date: 2018-04-03 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +[RFC 243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md#choice-of-keywords + +[RFC 243] left the choice of keyword for `catch { .. }` expressions unresolved. +This RFC settles the choice of keyword. Namely, it: + +1. reserves `try` as a keyword in edition 2018. +2. replaces `do catch { .. }` with `try { .. }` +3. does **not** reserve `catch` as a keyword. + +# Motivation +[motivation]: #motivation + +[catch_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md + +[catch_rfc_motivation]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md#catch-expressions + +This RFC does not motivate `catch { .. }` or `try { .. }` expressions. +To read the motivation for that, please consult [the original `catch` RFC][catch_rfc_motivation]. + +## For reserving a keyword + +Whatever keyword is chosen, it can't be contextual. + +As with `catch { .. }`, the syntactic form ` { .. }` where `` +is replaced with any possible keyword would conflict with a struct named +`` as seen in this perfectly legal snippet in Rust 2015, +where `` has been substituted for `try`: + +```rust +struct try; +fn main() { + try { + }; +} +``` + +### Aside note: + +The snippet above emits the following warning: + +``` +warning: type `try` should have a camel case name such as `Try` +``` + +which is also the case for `catch`. +This warning decreases the risk that someone has defined a type named `try` +anywhere in the ecosystem which happens to be beneficial to us. + +## For reserving `try` specifically + +This is discussed in the [Rationale][alternatives]. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +The keyword `try` will be reserved. +This will allow you to write expressions such as: + +```rust +try { + let x = foo?; + let y = bar?; + // Note: OK-wrapping is assumed here, but it is not the goal of this RFC + // to decide either in favor or against OK-wrapping. + x + y +} +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +[list of keywords]: https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html#keywords-currently-in-use + +The word `try` is reserved as a keyword in the [list of keywords] +in Rust edition 2018 and later editions. + +The keyword `try` is used in "try expressions" of the form `try { .. }`. + +# Drawbacks +[drawbacks]: #drawbacks + +There are two main drawbacks to the `try` keyword. + +## Association with exception handling - Both a pro and con + +> I think that there is a belief – one that I have shared from time to time – that it is not helpful to use familiar keywords unless the semantics are a perfect match, the concern being that they will setup an intuition that will lead people astray. I think that is a danger, but it works both ways: those intuitions also help people to understand, particularly in the early days. So it’s a question of “how far along will you get before the differences start to matter” and “how damaging is it if you misunderstand for a while”. +> +> [..] +> +> Rust has a lot of concepts to learn. If we are going to succeed, it’s essential that people can learn them a bit at a time, and that we not throw everything at you at once. I think we should always be on the lookout for places where we can build on intuitions from other languages; it doesn’t have to be a 100% match to be useful. + +\- [Niko Matsakis](https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/4) + +For some people, the association to `try { .. } catch { .. }` in languages such +as Java, and others in the [prior-art] section, is unhelpful wrt. teachability +because they see the explicit, reifed, and manually propagated exceptions in +Rust as something very different than the much more implicit exception handling +stories in Java et al. + +[`ExceptT`]: https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Except.html#t:ExceptT + +However, we make the case that other languages which do have these explicit and +reified exceptions as in Rust also use an exception vocabulary. +Notably, Haskell calls the monad-transformer for adding exceptions [`ExceptT`]. + +We also argue that even tho we are propagating exceptions manually, +we are following tradition in that other languages have very different +formulations of the exception idea. + +The benefit of familiarity, even if not a perfect match, as Niko puts it, +helps in learning, particularly because Rust is not a language in lack of +concepts to learn. + +[`try!`]: https://doc.rust-lang.org/nightly/std/macro.try.html + +## Breakage of the [`try!`] macro + +One possible result of introducing `try` as a keyword be that the old `try!` +macro would break. This could potentially be avoided but with great technical +challenges. + +With the prospect of breaking [`try!`], a few notes are in order: + +1. `?` was stabilized in 1.13, November 2016, which is roughly 1.4 years since + the date this RFC was started. +2. `try!` has been "deprecated" since then since: + > The `?` operator was added to replace `try!` and should be used instead. +3. `try!(expr)` can in virtually all instances be automatically `rustfix`ed + automatically to `expr?`. +4. There are very few questions on Stack Overflow that mention `try!`. +5. ["The Rust Programming Language", 2nd edition](https://doc.rust-lang.org/book/second-edition/) (book) and "Rust by Example" + have both already removed all mentions of `try!`. + +> So overall I think it’s feasible to reduce the `try!` macro to a historical curiosity to the point it won’t be actively confusing to newbies coming to Rust. + +\- [kornel](https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/49) + +However, + +1. There are still plenty of materials out there which mention `try!`. +2. `try!` is essentially the inverse of `try { .. }`. + +> Purging from the “collective memories of Rustaceans and Rust materials” is not something that easy. + +\- [Manish Goregaokar](https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/50) + +In the RFC author's opinion however, the sum total benefits of `try { .. }` +seem to outweigh the drawbacks of the difficulty with purging [`try!`] from +our collective memory. + +# Rationale and alternatives +[alternatives]: #alternatives + +## Review considerations + +Among the considerations when picking a keyword are, ordered by importance: + +1. Fidelity to the construct's actual behavior. + +2. Precedent from existing languages + 1. Popularity of the languages. + 2. Fidelity to behavior in those languages. + 3. Familiarity with respect to their analogous constructs. + + See the [prior art][prior-art] the [rationale for try] + for more discussion on precedent. + +2. Brevity. + +[`Try`]: https://doc.rust-lang.org/nightly/std/ops/trait.Try.html + +4. Consistency with the naming of the trait used for `?` (the [`Try`] trait). + +5. Consistency with related standard library function conventions. + +6. Degree / Risk of breakage. + +7. Consistency with old learning material. + + 1. Inversely: The extent of the old learning material + + That is, (in)consistency with `?` and the `try!()` macro. + If the first clause is called `try`, + then `try { }` and `try!()` would have essentially inverse meanings. + +## Rationale for `try` +[rationale for try]: #rationale-for-try + +1. **Fidelity to the construct's actual behavior:** Very high +2. **Precedent from existing languages:** + + `do`: Haskell, Idris + + `try`: A lot, see [prior-art] + 1. **Popularity of the languages:** Massive accumulated dominance + 2. **Fidelity to behavior in those languages:** Very high + 3. **Familiarity with respect to their analogous constructs:** Very high +3. **Brevity / Length:** 3 +4. **Consistency with the naming of the trait used for `?`:** Consistent +5. **Consistency with related libstd fn conventions:** Consistent +6. **Risk of breakage:** High (if we assume `try!` will break, otherwise: Low) + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=try), `std::try!`, but it is technically possible to not break this macro. (unstable: `std::intrinsics::try` so irrelevant) + - **Used as crate?** [*Yes*](https://crates.io/crates/try). No reverse dependencies. Described as: *"Deprecation warning resistant try macro"* + - **Usage (sourcegraph):** **27** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+try\s+=|(fn|impl|mod|struct|enum|union|trait)\s+try)\b + ``` +7. **Consistency with old learning material:** Inconsistent ([`try!`]) + +### Review + +This is our choice of keyword, because it: + +1. has a massive dominance in both popular and less known languages and is + sufficiently semantically faithful to what `try` means in those languages. +2. is consistent with the standard library wrt. `Try` and `try_` prefixed methods. +3. it is brief. +4. it has high fidelity wrt. the concepts it attempts to communicate (exception boundary for `?`). +5. it can be further extended with `catch { .. }` handlers if we wish. + +## Alternative: reserving `catch` + +1. **Fidelity to the construct's actual behavior:** Low +2. **Precedent from existing languages:** + + `do`: Haskell, Idris + + `try`: None +3. **Brevity / Length:** 6 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Somewhat consistent +6. **Risk of breakage:** Low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=catch) + - **Used as crate?** [*No*](https://crates.io/crates/catch). + - **Usage (sourcegraph):** **21** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+catch\s+=|(fn|impl|mod|struct|enum|union|trait)\s+catch)\b + ``` +7. **Consistency with old learning material:** Untaught + +### Review + +We believe `catch` to be a poor choice of keyword, because it: + +1. is used nowhere in other languages to demarcate the body which can result in + an exceptional path. Instead, it is almost exclusively used for exception + handlers of the form: `catch(pat) { recover_expr }`. +4. extending `catch` with handlers will require a different word such as + `handler` to get `catch { .. } handler(e) { .. }` semantics if we want. + This inversion compared to a lot of other languages will only harm + teachability of the language and steal a lot of our strangeness budget. +2. it is less brief than `try`. +3. the consistency wrt. methods in the standard library is low - + there's only `catch_unwind`, but that has to do with panics, + not `Try` style exceptions. + +## Alternative: keeping `do catch { .. }` + +1. **Fidelity to the construct's actual behavior:** High +2. **Precedent from existing languages:** + + `do`: Haskell, Idris + + `catch`: None, see [prior-art] +3. **Brevity / Length:** 8 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Tiny bit consistent +6. **Risk of breakage:** Impossible (already reserved keyword) + - **Used in std:** *No*, the form `$ident $ident` is not a legal identifier. + - **Used as crate?** *No*, as above. + - **Usage (sourcegraph):** **0** regex: N/A +7. **Consistency with old learning material:** Untaught + +An alternative would be to simply use the `do catch { ... }` syntax we have +in the nightly compiler. However, this syntax was not in the accepted `catch` +RFC and was only a temporarly fix around `catch { .. }` not working. + +## Alternative: `do try { .. }` + +1. **Fidelity to the construct's actual behavior:** High +2. **Precedent from existing languages:** + + `do`: Haskell, Idris + + `try`: A lot, see [prior-art] + 1. **Popularity of the languages:** Massive accumulated dominance + 2. **Fidelity to behavior in those languages:** High + 3. **Familiarity with respect to their analogous constructs:** High +3. **Brevity / Length:** 6 (including space) +4. **Consistency with the naming of the trait used for `?`:** Moderately consistent +5. **Consistency with related libstd fn conventions:** Moderately consistent +6. **Risk of breakage:** Impossible (already reserved keyword) + - **Used in std:** *No*, the form `$ident $ident` is not a legal identifier. + - **Used as crate?** *No*, as above. + - **Usage (sourcegraph):** **0** regex: N/A +7. **Consistency with old learning material:** Untaught + +### Review + +We could in fact decide to keep the `do`-prefix but change the suffix to `try`. +The benefit here would be two-fold: + ++ No keyword `try` would need to be introduced as `do` already is a keyword. + Therefore, the `try!` macro would not break. + ++ An association with monads due to `do`. This can be considered a benfit since + `try` can be seen as sugar for the family of error monads + (modulo kinks wrt. imperative flow), and thus, + the `do` prefix leads to a path of generality if more monads are introduced. + +The drawbacks would be: + ++ The wider association with monads can be seen as a drawback for those not + familiar with monads. + ++ `do try { .. }` over `try { .. }` adds a small degree of ergonomics overhead + but not much (3 characters including the space). However, the frequency with + which the `try { .. }` construct might be used can make the small overhead + accumulate to a significant overhead when a large codebase is considered. + +Other than this, the argument for `do try` over `do catch` boils down to an +argument of `try` over `catch`. + +## Alternative: using `do { .. }` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** Haskell, Idris + 1. **Popularity of the languages:** Haskell: Tiobe #42, PYPL #22 + 2. **Fidelity to behavior in those languages:** Good + 3. **Familiarity with respect to their analogous constructs:** Poor +3. **Brevity / Length:** 2 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Impossible (already reserved keyword) +7. **Consistency with old learning material:** Untaught + +### Review + +The keyword `do` was probably originally reserved for two use cases: + +1. `do while { .. }` + +2. Monadic `do`-notation a la Haskell: + + ```haskell + stuff = do + x <- actionX + y <- actionY x + z <- actionZ + sideEffect + finalAction x y z + ``` + + The which would be translated into the following pseudo-Rust: + + ```rust + let stuff = do { + x <- actionX; + y <- actionY(x); + z <- actionZ; + sideEffect; + finalAction(x, y, z); + }; + ``` + + Or particularly for the `try { .. }` case: + + ```rust + let stuff = try { + let x = actionX?; + let y = actionY(x)?; + let z = actionZ?; + sideEffect?; + finalAction(x, y, z) + }; + ``` + + The Haskell version is syntactic sugar for: + + ```haskell + stuff = actionX >>= + \x -> actionY x >>= + \y -> actionZ >>= + \z -> sideEffect >> + finalAction x y z + ``` + + or in Rust: + + ```rust + let stuff = + actionX.flat_map(|x| // or .and_then(..) + actionY(x).flat_map(|y| + actionZ.flat_map(|z| + sideEffect.flat_map(|_| + finalAction(x, y, z) + ) + ) + ) + ); + ``` + + In the Haskell version, `>>=` is defined in the `Monad` typeclass (trait): + + ```haskell + {-# LANGUAGE KindSignatures #-} + + class Applicative m => Monad (m :: * -> *) where + return :: a -> m a + (>>=) :: m a -> (a -> m b) -> m b + + (>>) :: m a -> m b -> m b + (>>) = \ma mb -> ma >>= \_ -> mb + ``` + + And some instances (impls) of `Monad` are: + + ```haskell + -- | Same as Option + data Maybe a = Nothing | Just a + + instance Monad Maybe where + return = Just + (Just a) >>= f = f a + _ >>= _ = Nothing + + -- | `struct Norm { value: T, normalized: bool }` + data Norm a = Norm a Bool + + instance Monad Norm where + return a = Norm a False + (Norm a u) >>= f = let Norm b w = f a in Norm b (u || w) + ``` + +[`MonadError`]: http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Error-Class.html#t:MonadError + +Considering the latter case of do-notation, +we saw how `try { .. }` and `do { .. }` relate. +In fact, `try { .. }` is special to the [`Try`] ([`MonadError`]) monads. +There are also more forms of monads which you might want to use `do { .. }` for. +Among these are: Futures, Iterators +Due to having more monads than [`Try`]-based ones, +using the `do { .. }` syntax directly as a replacement for `try { .. }` becomes +problematic as it: + +1. confuses everyone familiar with do-notation and monads. +2. is in the way of use for monads in general. +3. `do` is generic and unclear wrt. semantics. + +## Alternative: reserving `trap` + +1. **Fidelity to the construct's actual behavior:** Good +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 4 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=trap) + - **Used as crate?** [*No*](https://crates.io/crates/trap). + - **Usage (sourcegraph):** **4** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+trap\s+=|(fn|impl|mod|struct|enum|union|trait)\s+trap)\b + ``` +7. **Consistency with old learning material:** Untaught + +### Review + +Arguably, this candidate keyword is a somewhat a good choice. + +To `trap` an error is sufficently clear on the "exception boundary" semantics +we wish to communicate. + +However, `trap` is used as an error handler in at least one langauge. + +It also does not have the familiarity that `try` does have and is entirely +inconsistent wrt. naming in the standard library. + +## Alternative: a smattering of other possible keywords + +There are a host of other keywords which have been suggested. + +### `fallible` + +On an [internals thread](https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/), `fallible` was suggested. However, this keyword lacks the verb-form that +is the convention in Rust. Breaking with this convention should only be done +if there are significant reasons to do so, which do not seem to exist in this +case. It is also considerably longer than `try` (+5 character) which matters +for constructions which are oft used. + +1. **Fidelity to the construct's actual behavior:** High +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 8 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Highly inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=fallible) + - **Used as crate?** [*Yes*](https://crates.io/crates/fallible), some reverse dependencies (all by the same author). + - **Usage (sourcegraph)** [*None*](https://sourcegraph.com/search?q=repogroup:crates+case:yes++%5Cb%28%28let%7Cconst%7Ctype%7C%29%5Cs%2Bfallible%5Cs%2B%3D%7C%28fn%7Cimpl%7Cmod%7Cstruct%7Cenum%7Cunion%7Ctrait%29%5Cs%2Bfallible%29%5Cb+max:400) +7. **Consistency with old learning material:** Untaught + +### Synonyms of `catch`: + +Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/2): + +#### `accept` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 6 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Medium + - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=accept) + - **Used as crate?** [*No*](https://crates.io/crates/accept). + - **Usage (sourcegraph):** **79+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+accept\s+=|(fn|impl|mod|struct|enum|union|trait)\s+accept)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `capture` + +1. **Fidelity to the construct's actual behavior:** Good. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 7 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=capture) + - **Used as crate?** [*Yes*](https://crates.io/crates/capture), no reverse dependencies. + - **Usage (sourcegraph):** **6+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+capture\s+=|(fn|impl|mod|struct|enum|union|trait)\s+capture)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `collect` + +1. **Fidelity to the construct's actual behavior:** Very much not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 7 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very high + - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=collect) (`Iterator::collect`) + - **Used as crate?** [*Yes*](https://crates.io/crates/collect), no reverse dependencies. + - **Usage (sourcegraph):** **35+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+collect\s+=|(fn|impl|mod|struct|enum|union|trait)\s+collect)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `recover` + +1. **Fidelity to the construct's actual behavior:** Good +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 7 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=recover) + - **Used as crate?** [*No*](https://crates.io/crates/recover) + - **Usage (sourcegraph):** **4+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+recover\s+=|(fn|impl|mod|struct|enum|union|trait)\s+recover)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `resolve` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 7 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Low to medium + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=resolve) + - **Used as crate?** [*Yes*](https://crates.io/crates/resolve), 3 reverse dependencies + - **Usage (sourcegraph):** **50+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+resolve\s+=|(fn|impl|mod|struct|enum|union|trait)\s+resolve)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `take` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 4 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Huge + - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=take), `{Cell, HashSet, Read, Iterator, Option}::take`. + - **Used as crate?** [*Yes*](https://crates.io/crates/resolve), a lot of reverse dependency (transitive closure). + - **Usage (sourcegraph):** **62+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+take\s+=|(fn|impl|mod|struct|enum|union|trait)\s+take)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### Review + +Of these, only `recover` and `capture` seem reasonable semantically. +But `recover` is even more problematic than `catch` because it enhances +the feeling of exception-handling instead of exception-boundaries. +However, `capture` is reasonable as a substitute for `try`, +but it seems obscure and lacks familiarity, which is counted as a strong downside. + +### [and some other keywords:](https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/13) + +#### `coalesce` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 8 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Medium (itertools) + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=coalesce). + - **Used as crate?** [*Yes*](https://crates.io/crates/coalesce), one reverse dependency. + - **Usage (sourcegraph):** **3+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+coalesce\s+=|(fn|impl|mod|struct|enum|union|trait)\s+coalesce)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `fuse` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 4 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Medium (libstd) + - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=fuse), `Iterator::fuse`. + - **Used as crate?** [*Yes*](https://crates.io/crates/fuse), 8 reverse dependencies (transitive closure). + - **Usage (sourcegraph):** **8+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+fuse\s+=|(fn|impl|mod|struct|enum|union|trait)\s+fuse)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `unite` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 5 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=unite). + - **Used as crate?** [*No*](https://crates.io/crates/unite). + - **Usage (sourcegraph):** **0+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+unite\s+=|(fn|impl|mod|struct|enum|union|trait)\s+unite)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `cohere` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 6 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=cohere). + - **Used as crate?** [*No*](https://crates.io/crates/cohere). + - **Usage (sourcegraph):** **0+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+cohere\s+=|(fn|impl|mod|struct|enum|union|trait)\s+cohere)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `consolidate` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 11 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=consolidate). + - **Used as crate?** [*No*](https://crates.io/crates/consolidate). + - **Usage (sourcegraph):** **0+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+consolidate\s+=|(fn|impl|mod|struct|enum|union|trait)\s+consolidate)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `unify` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 5 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=unify). + - **Used as crate?** [*Yes*](https://crates.io/crates/unify), no dependencies + - **Usage (sourcegraph):** **1** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+take\s+=|(fn|impl|mod|struct|enum|union|trait)\s+take)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `combine` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 7 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Medium + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=combine). + - **Used as crate?** [*Yes*](https://crates.io/crates/combine), 17 (direct dependencies) + - **Usage (sourcegraph):** **6+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+combine\s+=|(fn|impl|mod|struct|enum|union|trait)\s+combine)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `resultof` + +1. **Fidelity to the construct's actual behavior:** Somewhat +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 8 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Very inconsistent (not verb) +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=resultof). + - **Used as crate?** [*No*](https://crates.io/crates/resultof). + - **Usage (sourcegraph):** **0+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+resultof\s+=|(fn|impl|mod|struct|enum|union|trait)\s+resultof)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### `returned` + +1. **Fidelity to the construct's actual behavior:** Not at all. +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 8 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Very inconsistent +6. **Risk of breakage:** + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=returned). + - **Used as crate?** [*No*](https://crates.io/crates/returned). + - **Usage (sourcegraph):** **0+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+returned\s+=|(fn|impl|mod|struct|enum|union|trait)\s+returned)\b + ``` +7. **Consistency with old learning material:** Untaught + +#### Review + +Of these, only `resultof` seems to be semantically descriptive and has some support. However, it has three major drawbacks: + ++ Length: Compared to `try`, it is 5 characters longer (see reasoning for `fallible`). + ++ Not a word: `resultof` is in fact a concatenation of `result` and `of`. + This does not feel like a natural fit for Rust, as we tend to use a `_` separator. + Furthermore, there are no current keywords in use that are concatenations of two word. + ++ `Result` oriented: `resultof` is too tied to `Result` and fits poorly with `Option` or other types that implement `Try`. + +# Prior art +[prior-art]: #prior-art + +All of the languages listed below have a `try { .. } { .. }` concept +(modulo layout syntax / braces) where `` is one of: +`catch`, `with`, `except`, `trap`, `rescue`. + +In total, these are 27 languages and they have massive ~80% dominance according +to the [TIOBE index](https://www.tiobe.com/tiobe-index/) +and roughly the same with the [PYPL index](http://pypl.github.io/PYPL.html). + ++ [C++](http://en.cppreference.com/w/cpp/language/try_catch) ++ [D](https://tour.dlang.org/tour/en/basics/exceptions) ++ [C#](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch) ++ [Java](https://docs.oracle.com/javase/tutorial/essential/exceptions/try.html) ++ [Scala](https://stackoverflow.com/questions/18685573/try-catch-finally-return-value) ++ [Kotlin](https://kotlinlang.org/docs/reference/exceptions.html) ++ [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) ++ [TypeScript](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-5.html) ++ [ActionScript](https://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7ed1.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7ec5) ++ [Dart](https://www.dartlang.org/resources/dart-tips/dart-tips-ep-9) ++ [Python](https://docs.python.org/3/tutorial/errors.html) ++ [PHP](http://php.net/manual/en/language.exceptions.php) ++ [Matlab](https://se.mathworks.com/help/matlab/ref/try.html) ++ [Visual Basic](https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/try-catch-finally-statement) ++ [OCaml](https://ocaml.org/learn/tutorials/error_handling.html) ++ [F#](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/exception-handling/the-try-with-expression) ++ [Objective C](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html#//apple_ref/doc/uid/TP40011210-CH9-SW3) ++ [Swift](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html) ++ [Delphi](https://stackoverflow.com/questions/6601147/how-to-correctly-write-try-finally-except-statements) ++ [Julia](https://docs.julialang.org/en/stable/manual/control-flow/#The-try/catch-statement-1) ++ [Elixir](https://elixir-lang.org/getting-started/try-catch-and-rescue.html) ++ [Erlang](http://erlang.org/doc/reference_manual/expressions.html#try) ++ [Clojure](https://clojuredocs.org/clojure.core/try) ++ [R](https://www.rdocumentation.org/packages/base/versions/3.0.3/topics/conditions), modulo minor syntactic difference. ++ [Powershell](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-6) ++ [Tcl](http://wiki.tcl.tk/8293) ++ [Apex](https://developer.salesforce.com/page/An_Introduction_to_Exception_Handling) ++ [RPG](http://devnet.asna.com/documentation/Help102/AVR/_HTML/TRYCATCHFINALLY.htm) ++ [ABAP](https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abaptry.htm) + +The syntactic form `catch { .. }` seems quite rare and is, +together with `trap`, `rescue`, `except`, only used for handlers. +However, the ` { .. }` expression we want to introduce is not a handler, +but rather the body of expression we wish to `try`. + +# Unresolved questions +[unresolved]: #unresolved-questions + +None as of yet. \ No newline at end of file From 88b94dd5d6412c9ed7ef80cb1371a1e2c3e2960f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Apr 2018 20:20:02 +0200 Subject: [PATCH 02/11] rfc, try-expr: fix link --- text/0000-try-expr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index b306be66650..0756ba3c7f7 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -56,7 +56,7 @@ anywhere in the ecosystem which happens to be beneficial to us. ## For reserving `try` specifically -This is discussed in the [Rationale][alternatives]. +This is discussed in the [rationale for `try`][rationale for try]. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -157,7 +157,7 @@ seem to outweigh the drawbacks of the difficulty with purging [`try!`] from our collective memory. # Rationale and alternatives -[alternatives]: #alternatives +[rationale-and-alternatives]: #rationale-and-alternatives ## Review considerations From 6888455a1da83b7d31df4a9b4998794ac6c69b7e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Apr 2018 20:29:55 +0200 Subject: [PATCH 03/11] rfc, try-expr: fix date --- text/0000-try-expr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index 0756ba3c7f7..df9558106b6 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -1,5 +1,5 @@ - Feature Name: `try_expr` -- Start Date: 2018-04-03 +- Start Date: 2018-04-04 - RFC PR: (leave this empty) - Rust Issue: (leave this empty) @@ -831,4 +831,4 @@ but rather the body of expression we wish to `try`. # Unresolved questions [unresolved]: #unresolved-questions -None as of yet. \ No newline at end of file +None as of yet. From 100a626570ee77a82c08587f970b52053c545700 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Apr 2018 20:33:43 +0200 Subject: [PATCH 04/11] rfc, try-expr: fix copy error wrt. fidelity of do catch { .. }. --- text/0000-try-expr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index df9558106b6..8d322caf2b7 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -262,7 +262,7 @@ We believe `catch` to be a poor choice of keyword, because it: ## Alternative: keeping `do catch { .. }` -1. **Fidelity to the construct's actual behavior:** High +1. **Fidelity to the construct's actual behavior:** Low 2. **Precedent from existing languages:** + `do`: Haskell, Idris + `catch`: None, see [prior-art] From 42331a911432515b2056286381da763c09d7893a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Apr 2018 20:50:06 +0200 Subject: [PATCH 05/11] rfc, try-expr: review 'result' keyword. --- text/0000-try-expr.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index 8d322caf2b7..b204479f4f0 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -478,6 +478,36 @@ However, `trap` is used as an error handler in at least one langauge. It also does not have the familiarity that `try` does have and is entirely inconsistent wrt. naming in the standard library. +## Alternative: reserving `result` + +1. **Fidelity to the construct's actual behavior:** Somewhat good +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 6 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very high + - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=result) for the `{std, core}::result` modules. + - **Used as crate?** [*Yes*](https://crates.io/crates/result). 6 reverse dependencies (transitive closure). + - **Usage (sourcegraph):** **43+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+result\s+=|(fn|impl|mod|struct|enum|union|trait)\s+result)\b + ``` +7. **Consistency with old learning material:** Untaught + +## Review + +[final encoding]: http://okmij.org/ftp/tagless-final/course/lecture.pdf + +The fidelity of `result` is somewhat good due to the association with the +`Result` type as well as `Try` being a [final encoding] of `Result`. + +However, when you consider `Option`, the association is less direct, +and thus it does not fit `Option` and other types well. + +The breakage of the `result` module is however quite problematic, +making this particular choice of keyword more or less a non-starter. + ## Alternative: a smattering of other possible keywords There are a host of other keywords which have been suggested. From dd0141a8d3a8ff61f5df71554f75148f60be731f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 5 Apr 2018 20:08:29 +0200 Subject: [PATCH 06/11] rfc, try-expr: discuss `wrap` as an alternative. --- text/0000-try-expr.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index b204479f4f0..93d45707a13 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -478,6 +478,32 @@ However, `trap` is used as an error handler in at least one langauge. It also does not have the familiarity that `try` does have and is entirely inconsistent wrt. naming in the standard library. +## Alternative: reserving `wrap` + +1. **Fidelity to the construct's actual behavior:** Somewhat good +2. **Precedent from existing languages:** None +3. **Brevity / Length:** 4 +4. **Consistency with the naming of the trait used for `?`:** Inconsistent +5. **Consistency with related libstd fn conventions:** Inconsistent +6. **Risk of breakage:** Very low + - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=wrap) + - **Used as crate?** [*Yes*](https://crates.io/crates/wrap), no reverse dependencies. + - **Usage (sourcegraph):** **37+** regex: + ``` + repogroup:crates case:yes max:400 + \b((let|const|type|)\s+wrap\s+=|(fn|impl|mod|struct|enum|union|trait)\s+wrap)\b + ``` +7. **Consistency with old learning material:** Untaught + +### Review + +With `wrap { .. }` we can say that it "wraps" the result of the block as a +`Result` / `Option`, etc. and it is logically related to `.unwrap()`, +which is however a partial function, wherefore the connotation might be bad. + +Also, `wrap` could be considered too generic as with `do` in that it could +fit for any monad. + ## Alternative: reserving `result` 1. **Fidelity to the construct's actual behavior:** Somewhat good From 628d78a8233cf8e2a6d0069e4a23cdb085b7d37b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 5 Apr 2018 22:43:58 +0200 Subject: [PATCH 07/11] rfc, try-expr: fix copy error wrt. `try` vs `do try`. --- text/0000-try-expr.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index 93d45707a13..16df434439b 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -195,9 +195,7 @@ Among the considerations when picking a keyword are, ordered by importance: [rationale for try]: #rationale-for-try 1. **Fidelity to the construct's actual behavior:** Very high -2. **Precedent from existing languages:** - + `do`: Haskell, Idris - + `try`: A lot, see [prior-art] +2. **Precedent from existing languages:** A lot, see [prior-art] 1. **Popularity of the languages:** Massive accumulated dominance 2. **Fidelity to behavior in those languages:** Very high 3. **Familiarity with respect to their analogous constructs:** Very high From 1d1bd0d73c6d231c4dc72a34c1894f4958c5aabe Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 5 Apr 2018 22:48:13 +0200 Subject: [PATCH 08/11] rfc, try-expr: fix copy error wrt. `catch` vs. `do catch`. --- text/0000-try-expr.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index 16df434439b..4def1fe255e 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -226,9 +226,7 @@ This is our choice of keyword, because it: ## Alternative: reserving `catch` 1. **Fidelity to the construct's actual behavior:** Low -2. **Precedent from existing languages:** - + `do`: Haskell, Idris - + `try`: None +2. **Precedent from existing languages:** None 3. **Brevity / Length:** 6 4. **Consistency with the naming of the trait used for `?`:** Inconsistent 5. **Consistency with related libstd fn conventions:** Somewhat consistent From 5ac3821154b6eeff684ab331244f73401f78ba9c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 12 Apr 2018 20:20:59 +0200 Subject: [PATCH 09/11] rfc, try-expr: adress some comments --- text/0000-try-expr.md | 146 +++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 58 deletions(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index 4def1fe255e..1f34ad60c6b 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -156,6 +156,19 @@ In the RFC author's opinion however, the sum total benefits of `try { .. }` seem to outweigh the drawbacks of the difficulty with purging [`try!`] from our collective memory. +## Inverse semantics of `?` + +The `?` postfix operator is sometimes referred to as the "try operator", +and can be seen as having the inverse semantics as `try { .. }`. + +To many, this is a drawback. To others, this makes the `?` and `try { .. }` +expression forms more closely related and therefore makes them more findable +in relation to each other. + +There is currently some ongoing debate about renaming the `?` operator to +something other than the "try operator". This could help in mitigating the +effects of picking `try` as the keyword. + # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives @@ -177,9 +190,11 @@ Among the considerations when picking a keyword are, ordered by importance: [`Try`]: https://doc.rust-lang.org/nightly/std/ops/trait.Try.html -4. Consistency with the naming of the trait used for `?` (the [`Try`] trait). +4. Consistency with related standard library function conventions. -5. Consistency with related standard library function conventions. +5. Consistency with the naming of the trait used for `?` (the [`Try`] trait). + Since the `Try` trait is unstable and the naming of the `?` operator in + communication is still unsettled, this is not regarded as very important. 6. Degree / Risk of breakage. @@ -200,8 +215,8 @@ Among the considerations when picking a keyword are, ordered by importance: 2. **Fidelity to behavior in those languages:** Very high 3. **Familiarity with respect to their analogous constructs:** Very high 3. **Brevity / Length:** 3 -4. **Consistency with the naming of the trait used for `?`:** Consistent -5. **Consistency with related libstd fn conventions:** Consistent +4. **Consistency with related libstd fn conventions:** Consistent +5. **Consistency with the naming of the trait used for `?`:** Consistent 6. **Risk of breakage:** High (if we assume `try!` will break, otherwise: Low) - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=try), `std::try!`, but it is technically possible to not break this macro. (unstable: `std::intrinsics::try` so irrelevant) - **Used as crate?** [*Yes*](https://crates.io/crates/try). No reverse dependencies. Described as: *"Deprecation warning resistant try macro"* @@ -218,18 +233,22 @@ This is our choice of keyword, because it: 1. has a massive dominance in both popular and less known languages and is sufficiently semantically faithful to what `try` means in those languages. + Thus, we can leverage people's intuitions and not spend too much of our + complexity budget. 2. is consistent with the standard library wrt. `Try` and `try_` prefixed methods. -3. it is brief. -4. it has high fidelity wrt. the concepts it attempts to communicate (exception boundary for `?`). +3. it is brief. +4. it has high fidelity wrt. the concepts it attempts to communicate + (exception boundary for `?`). This high fidelity is from the perspective of + a programmers intent, i.e: "I want to try a bunch of stuff in this block". 5. it can be further extended with `catch { .. }` handlers if we wish. ## Alternative: reserving `catch` -1. **Fidelity to the construct's actual behavior:** Low -2. **Precedent from existing languages:** None +1. **Fidelity to the construct's actual behavior:** High +2. **Precedent from existing languages:** Erlang and Tcl, see [prior-art] 3. **Brevity / Length:** 6 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Somewhat consistent +4. **Consistency with related libstd fn conventions:** Somewhat consistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=catch) - **Used as crate?** [*No*](https://crates.io/crates/catch). @@ -244,7 +263,7 @@ This is our choice of keyword, because it: We believe `catch` to be a poor choice of keyword, because it: -1. is used nowhere in other languages to demarcate the body which can result in +1. is used in few in other languages to demarcate the body which can result in an exceptional path. Instead, it is almost exclusively used for exception handlers of the form: `catch(pat) { recover_expr }`. 4. extending `catch` with handlers will require a different word such as @@ -256,15 +275,18 @@ We believe `catch` to be a poor choice of keyword, because it: there's only `catch_unwind`, but that has to do with panics, not `Try` style exceptions. +However, `catch` has high fidelity wrt. the operational semantics of "catching" +any exceptions in the `try { .. }` block. + ## Alternative: keeping `do catch { .. }` -1. **Fidelity to the construct's actual behavior:** Low +1. **Fidelity to the construct's actual behavior:** Middle 2. **Precedent from existing languages:** + `do`: Haskell, Idris - + `catch`: None, see [prior-art] + + `catch`: Erlang and Tcl, see [prior-art] 3. **Brevity / Length:** 8 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Tiny bit consistent +4. **Consistency with related libstd fn conventions:** Tiny bit consistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Impossible (already reserved keyword) - **Used in std:** *No*, the form `$ident $ident` is not a legal identifier. - **Used as crate?** *No*, as above. @@ -285,8 +307,8 @@ RFC and was only a temporarly fix around `catch { .. }` not working. 2. **Fidelity to behavior in those languages:** High 3. **Familiarity with respect to their analogous constructs:** High 3. **Brevity / Length:** 6 (including space) -4. **Consistency with the naming of the trait used for `?`:** Moderately consistent -5. **Consistency with related libstd fn conventions:** Moderately consistent +4. **Consistency with related libstd fn conventions:** Moderately consistent +5. **Consistency with the naming of the trait used for `?`:** Moderately consistent 6. **Risk of breakage:** Impossible (already reserved keyword) - **Used in std:** *No*, the form `$ident $ident` is not a legal identifier. - **Used as crate?** *No*, as above. @@ -327,8 +349,8 @@ argument of `try` over `catch`. 2. **Fidelity to behavior in those languages:** Good 3. **Familiarity with respect to their analogous constructs:** Poor 3. **Brevity / Length:** 2 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Impossible (already reserved keyword) 7. **Consistency with old learning material:** Untaught @@ -450,8 +472,8 @@ problematic as it: 1. **Fidelity to the construct's actual behavior:** Good 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 4 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=trap) - **Used as crate?** [*No*](https://crates.io/crates/trap). @@ -479,8 +501,8 @@ inconsistent wrt. naming in the standard library. 1. **Fidelity to the construct's actual behavior:** Somewhat good 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 4 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=wrap) - **Used as crate?** [*Yes*](https://crates.io/crates/wrap), no reverse dependencies. @@ -505,8 +527,8 @@ fit for any monad. 1. **Fidelity to the construct's actual behavior:** Somewhat good 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 6 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very high - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=result) for the `{std, core}::result` modules. - **Used as crate?** [*Yes*](https://crates.io/crates/result). 6 reverse dependencies (transitive closure). @@ -545,8 +567,8 @@ for constructions which are oft used. 1. **Fidelity to the construct's actual behavior:** High 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 8 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Highly inconsistent +4. **Consistency with related libstd fn conventions:** Highly inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=fallible) - **Used as crate?** [*Yes*](https://crates.io/crates/fallible), some reverse dependencies (all by the same author). @@ -562,8 +584,8 @@ Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 6 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Medium - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=accept) - **Used as crate?** [*No*](https://crates.io/crates/accept). @@ -579,8 +601,8 @@ Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t 1. **Fidelity to the construct's actual behavior:** Good. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 7 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=capture) - **Used as crate?** [*Yes*](https://crates.io/crates/capture), no reverse dependencies. @@ -596,8 +618,8 @@ Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t 1. **Fidelity to the construct's actual behavior:** Very much not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 7 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very high - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=collect) (`Iterator::collect`) - **Used as crate?** [*Yes*](https://crates.io/crates/collect), no reverse dependencies. @@ -613,8 +635,8 @@ Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t 1. **Fidelity to the construct's actual behavior:** Good 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 7 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=recover) - **Used as crate?** [*No*](https://crates.io/crates/recover) @@ -630,8 +652,8 @@ Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 7 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Low to medium - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=resolve) - **Used as crate?** [*Yes*](https://crates.io/crates/resolve), 3 reverse dependencies @@ -647,8 +669,8 @@ Some synonyms of `catch` [have been suggested](https://internals.rust-lang.org/t 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 4 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Huge - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=take), `{Cell, HashSet, Read, Iterator, Option}::take`. - **Used as crate?** [*Yes*](https://crates.io/crates/resolve), a lot of reverse dependency (transitive closure). @@ -674,8 +696,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 8 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Medium (itertools) - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=coalesce). - **Used as crate?** [*Yes*](https://crates.io/crates/coalesce), one reverse dependency. @@ -691,8 +713,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 4 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Medium (libstd) - **Used in std:** [*Yes*](https://doc.rust-lang.org/nightly/std/?search=fuse), `Iterator::fuse`. - **Used as crate?** [*Yes*](https://crates.io/crates/fuse), 8 reverse dependencies (transitive closure). @@ -708,8 +730,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 5 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=unite). - **Used as crate?** [*No*](https://crates.io/crates/unite). @@ -725,8 +747,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 6 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=cohere). - **Used as crate?** [*No*](https://crates.io/crates/cohere). @@ -742,8 +764,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 11 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=consolidate). - **Used as crate?** [*No*](https://crates.io/crates/consolidate). @@ -759,8 +781,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 5 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=unify). - **Used as crate?** [*Yes*](https://crates.io/crates/unify), no dependencies @@ -776,8 +798,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 7 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Inconsistent +4. **Consistency with related libstd fn conventions:** Inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Medium - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=combine). - **Used as crate?** [*Yes*](https://crates.io/crates/combine), 17 (direct dependencies) @@ -793,8 +815,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Somewhat 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 8 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Very inconsistent (not verb) +4. **Consistency with related libstd fn conventions:** Very inconsistent (not verb) +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** Very low - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=resultof). - **Used as crate?** [*No*](https://crates.io/crates/resultof). @@ -810,8 +832,8 @@ but it seems obscure and lacks familiarity, which is counted as a strong downsid 1. **Fidelity to the construct's actual behavior:** Not at all. 2. **Precedent from existing languages:** None 3. **Brevity / Length:** 8 -4. **Consistency with the naming of the trait used for `?`:** Inconsistent -5. **Consistency with related libstd fn conventions:** Very inconsistent +4. **Consistency with related libstd fn conventions:** Very inconsistent +5. **Consistency with the naming of the trait used for `?`:** Inconsistent 6. **Risk of breakage:** - **Used in std:** [*No*](https://doc.rust-lang.org/nightly/std/?search=returned). - **Used as crate?** [*No*](https://crates.io/crates/returned). @@ -841,7 +863,7 @@ All of the languages listed below have a `try { .. } { .. }` concep (modulo layout syntax / braces) where `` is one of: `catch`, `with`, `except`, `trap`, `rescue`. -In total, these are 27 languages and they have massive ~80% dominance according +In total, these are 29 languages and they have massive ~80% dominance according to the [TIOBE index](https://www.tiobe.com/tiobe-index/) and roughly the same with the [PYPL index](http://pypl.github.io/PYPL.html). @@ -880,6 +902,14 @@ together with `trap`, `rescue`, `except`, only used for handlers. However, the ` { .. }` expression we want to introduce is not a handler, but rather the body of expression we wish to `try`. +There are however a few languages where `catch { .. }` is used for the fallible +part and not for the handler, these languages are: ++ [Erlang](http://erlang.org/doc/reference_manual/expressions.html#catch) ++ [Tcl](https://www.tcl.tk/man/tcl/TclCmd/catch.htm) + +However, the combined popularity of these langauges are not significant as +compared to that for `try { .. }`. + # Unresolved questions [unresolved]: #unresolved-questions From edddfb39ba7ee5646163047c688d493c0f49fb65 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 27 Apr 2018 22:43:57 +0200 Subject: [PATCH 10/11] rfc, try-expr: fix typo: reifed -> reified. --- text/0000-try-expr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-try-expr.md b/text/0000-try-expr.md index 1f34ad60c6b..f27fe8ed43a 100644 --- a/text/0000-try-expr.md +++ b/text/0000-try-expr.md @@ -101,7 +101,7 @@ There are two main drawbacks to the `try` keyword. For some people, the association to `try { .. } catch { .. }` in languages such as Java, and others in the [prior-art] section, is unhelpful wrt. teachability -because they see the explicit, reifed, and manually propagated exceptions in +because they see the explicit, reified, and manually propagated exceptions in Rust as something very different than the much more implicit exception handling stories in Java et al. From f1d4f6a8a67a2a78eb8b6bbba8a84cd7064236a7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 3 May 2018 09:34:26 +0200 Subject: [PATCH 11/11] RFC 2388 --- text/{0000-try-expr.md => 2388-try-expr.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename text/{0000-try-expr.md => 2388-try-expr.md} (99%) diff --git a/text/0000-try-expr.md b/text/2388-try-expr.md similarity index 99% rename from text/0000-try-expr.md rename to text/2388-try-expr.md index f27fe8ed43a..d21c6929fcb 100644 --- a/text/0000-try-expr.md +++ b/text/2388-try-expr.md @@ -1,7 +1,7 @@ - Feature Name: `try_expr` - Start Date: 2018-04-04 -- RFC PR: (leave this empty) -- Rust Issue: (leave this empty) +- RFC PR: [rust-lang/rfcs#2388](https://github.com/rust-lang/rfcs/pull/2388) +- Rust Issue: [rust-lang/rust#50412](https://github.com/rust-lang/rust/issues/50412) # Summary [summary]: #summary