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

Generic let #2297

Closed
SoniEx2 opened this issue Jan 17, 2018 · 4 comments
Closed

Generic let #2297

SoniEx2 opened this issue Jan 17, 2018 · 4 comments
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@SoniEx2
Copy link

SoniEx2 commented Jan 17, 2018

I'm tired of writing code like the following:

impl<'a> IrcCommand<'a> {
    pub fn new(cmd: &'a [u8]) -> IrcCommand<'a> {
        if cmd.len() == 3 && match (cmd[0], cmd[1], cmd[2]) {
            (b'0'...b'9', b'0'...b'9', b'0'...b'9') => {
                // TODO switch to TryFrom/TryInto once those are stable. (rust-lang/rust#33417)
                return IrcCommand::Numeric(Numeric::new(array_ref![cmd,0,3]));
            },
            _ => false
        } {
            unreachable!()
        } else {
            IrcCommand::Stringy(Stringy(cmd))
        }
    }
}

With generic let, I'd be able to write instead:

impl<'a> IrcCommand<'a> {
    pub fn new(cmd: &'a [u8]) -> IrcCommand<'a> {
        if cmd.len() == 3 && let (b'0'...b'9', b'0'...b'9', b'0'...b'9') = (cmd[0], cmd[1], cmd[2]) {
            // TODO switch to TryFrom/TryInto once those are stable. (rust-lang/rust#33417)
            IrcCommand::Numeric(Numeric::new(array_ref![cmd,0,3]))
        } else {
            IrcCommand::Stringy(Stringy(cmd))
        }
    }
}

Generic let works as follows:

let pattern = value becomes an expression, its return value is true if the pattern matches (always true for irrefutable patterns), false if it doesn't.

It binds the names when it matches, and only when it matches, so the compiler needs to check the true path for the names, and the false path for the lack of the names.

In the case of irrefutable patterns, the result is always true, so this is always valid:

let x = 1u8;
// this path is always true
println!("{}", x);

Using a refutable pattern in that let would cause the compiler to error.

Other cases where this is nice:

#2086 #935 etc.

while let data = do_some_io()? { // while we have lines
    println!("{}", data); // print the lines
}
if let Some(x @ '0'...'9' | x @ 'A'...'F' | x @ 'a'...'f') = v {
    println!("got hex: {}", x);
}
// OR
if (let Some(x @ '0'...'9') = v) || (let Some(x @ 'A'...'F') = v) || let Some(x @ 'a'...'f') = v { // note that "x" must appear in every || case.
    println!("got hex: {}", x);
}
// (with a strong preference for the former, ofc, as the latter needs parens)

Corner cases:

  • let would have the same precedence it does today. this means in patterns, you'd have to write if (let x = y) && ... (parens required except as the last expr). but it does give backwards compatibility with basically anything you can think of: if let true = p && q {, etc would still work.
  • I can't think of any other corner cases because every corner case I can think of is either an explicit consequence of this feature (e.g. irrefutable patterns in if-let and while-let, which still give a compiler warning as proposed in RFC: Allow Irrefutable Patterns in if-let and while-let statements #2086 as the compiler can guarantee it's always true and while true {} gives a warning), or it doesn't work and still won't work even with this feature.
@Centril Centril added the T-lang Relevant to the language team, which will review and decide on the RFC. label Jan 17, 2018
@Centril
Copy link
Contributor

Centril commented Jan 17, 2018

See the latest inception of this idea (not making let PAT = EXPR a general bool-typed expression tho) #2260 .

@Manishearth
Copy link
Member

Yeah, this is a dupe of #2260. That RFC doesn't propose exactly the same thing, however it's in the same design space.

@SoniEx2
Copy link
Author

SoniEx2 commented Jan 17, 2018

That RFC is closed. I'm trying to start fresh.

@Manishearth
Copy link
Member

I suggest opening a new one or starting a discussion on internals.rust-lang.org, I don't really think the issues on this repo is where you make specific suggestions, more for identifying general areas that need to be addressed with an RFC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

3 participants