From 144a30f877cbf903673903328230443b6dceef67 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 13 Jul 2018 02:51:32 +0200 Subject: [PATCH 01/15] rfc, let_chains_2: initial version. --- text/0000-if-let-chains.md | 2000 ++++++++++++++++++++++++++++++++++++ 1 file changed, 2000 insertions(+) create mode 100644 text/0000-if-let-chains.md diff --git a/text/0000-if-let-chains.md b/text/0000-if-let-chains.md new file mode 100644 index 00000000000..493f6ecad37 --- /dev/null +++ b/text/0000-if-let-chains.md @@ -0,0 +1,2000 @@ +- Feature Name: `let_chains_2` +- Start Date: 2018-07-13 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +Extends `if let` and `while let`-expressions with chaining, allowing you +to combine multiple `let`s and `bool`-typed conditions together naturally. +After implementing this RFC, you'll be able to write, among other things: + +```rust +fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { + if let Some(Def::Existential(_)) = tcx.describe_def(def_id) && + let Some(node_id) = tcx.hir.as_local_node_id(def_id) && + let hir::map::NodeItem(item) = tcx.hir.get(node_id) && + let hir::ItemExistential(ref exist_ty) = item.node && + let Some(parent) = exist_ty.impl_trait_fn { + return param_env(tcx, parent); + } + + ... +} +``` + +and with side effects: + +```rust +while let Ok(user) = read_user(::std::io::stdin()) + && user.name == "Alan Turing" + && let Ok(hobby) = read_hobby_of(&user) +{ + if hobby == "Hacking Enigma" { + println!("Yep, It's you."); + return Some(read_encrypted_stuff()); + } else { + println!("You can't be Alan! "); + } +} + +return None; +``` + +The main aim of this RFC is to decide that this is a problem worth solving +as well as discussing a few available options. **Most importantly, we want to +make `let PAT = EXPR && ..` a possible option for Rust 2018.** + +# Motivation +[motivation]: #motivation + +The main motivation for this RFC is improving readability, ergonomics, +and reducing paper cuts. + +## Right-ward drift + +Today, each `if let` needs a brace, which means that you usually, to keep +the code readable, indent once to the right each time. Thus, matching multiple +things quickly leads to way too much indent that overflows the typical +text editor or IDE horizontally. This is in particular bad for readers that +can only fit around 80-100 characters per line in their editor. Keeping in +mind that code is read more than written, it is important to improve readability +where possible. + +### Other solution: Tuples + +One solution is matching a tuple, but that is a poor solution when there are +side effects or expensive computations involved, and doesn't necessarily work +as *DSTs* and *lvalues* can't go in tuples. + +### Other solution: `break ...` + +Another solution to avoid right-ward drift is to create a new function for +part of the indentation. When the inner scopes depend on a lot of variables +and state from outer scopes, all of these variables have to be passed on to +the newly created function, which may not even be a natural unit to abstract +into a function. Creating a new function, especially one that feels artificial, +can also inhibit local reasoning. A new level of function (or [IIFE]) also +changes the behaviour of `return`, `break`, `?`, and friends. + +[IIFE]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression + +A third solution involves using the expression form `break '