Return with limited-choice enum ! (like java throws)

Hello,

I have a proposal, I've encountered this case several times, I have a function that returns an enum, but only a few elements of that enum, and so when I call this function, I will of course use a "match" to manage the return cases, except that Rust/Rust-analyzer can't determine that the function returns only a few elements of that enum, and so will force me to manage all the cases or use " _ " (catch-all pattern).

that reminded me that in Java we can define "throws" to say that this function returns only these exceptions.

so why not add the ability to define a limited-choice enum to Rust?

Let's take this simplified code to illustrate the problem :

enum Exception {
    InternalError(),
    IOError(),
    DBError(),
    XXXError(),
}

fn test() -> Result<(), Exception> {
    // code here
    if true {
        Err(Exception::DBError())
    } else {
        Err(Exception::IOError())
    }
}

fn main() {
    match test() {
        Ok(_) => println!("Cool"),
        Err(e) => match e {
            Exception::InternalError() => todo!(),//<----- it will never happen
            Exception::IOError() => todo!(),
            Exception::DBError() => todo!(),
            Exception::XXXError() => todo!(),//<----- it will never happen
        },
    }
}

we'll add a syntax to tell the compiler that I'm returning an enum, but limited to these two choices :

Result<(), Exception {DBError,IOError}>

fn test() -> Result<(), Exception {DBError,IOError}> { //<---------  limited-choice enum  :D
    // code here
    if true {
        Err(Exception::DBError())
    } else {
        Err(Exception::IOError())
    }
}

now the IDE can automatically fill the match with the two choices, and that makes life easier, since we don't have to read the function code every time to know which element of the enum it returns, or use "_" to save headache.

(and the compiler won't force us to handle the other cases as well, since it now knows that we're only returning these 2 cases.)

fn main() {
    match test() {
        Ok(_) => println!("Cool"),
        Err(e) => match e {
            Exception::IOError() => todo!(),
            Exception::DBError() => todo!(),
        },
    }
}

imagine the case of an enum with 100 elements, we'll always use "_ => " and that makes the code less meaningful, and it's a risk of errors: if the function afterwards returns a new type of exception, we simply can't handle it, since the "_" hides it.

what do you think? :thinking:

It sounds like this would "fall out" of a combination of variant types and anonymous enums.

Some previous discussion:

8 Likes

There's a proposal in the works now for "pattern types" which would do exactly what you're looking for.

14 Likes

Thank you very much for your answers, I hope that it will be integrated into Rust soon, because it is really a must for usability. :pray:

1 Like

You might be interested in cex and here is the documentation

Years ago I wrote a macro that does something similar: GitHub - idanarye/rust-powerset-enum

The result is a bit hideous, and I'd really prefer to be able to construct an unnamed enum (or enum-like thingie) from types rather than restrict an existing enum.

Look up the conversation about "pattern types".

3 Likes