Safe unions and error types

Currently there's some workarounds to deal with multiple error types other than creating a sum type, like dyn or anyhow.

The idea here is to make the compiler generate this sum type and allow transparent construction and matching.

union Error = Utf8Error | ParseIntError;

// translates to
// enum Error { _anon0(Utf8Error), _anon1(ParseIntError) }

fn convert(bytes: &[u8]) -> Result<i32, Error> {
 let s = std::str::from_utf8(bytes)?;    // auto-wraps into Error
 let n: i32 = s.trim().parse()?;         // auto-wraps into Error
 Ok(n)
}

match convert(bytes) {
	 Ok(n) => println!("{n}"),
	 Err(err @ Utf8Error) => { .. }
	 Err(err @ ParseIntError) => { .. }
}

Since it compiles down to a regular enum type, it would be a 'safe' union type compared to the one currently available.

Note that nested unions get flattened out,

union X = A | B;
union Y = C | D;
union Z = X | Y;

// translates to
// enum Z { _anon0(A), _anon1(B), _anon2(C), _anon3(D), }

which is considerably simpler to match as in match z { A | B | C | D => {} }.

Without any comment on the proposal, I would like to mention the error_set crate, which offers a nice way to achieve something very similar. It might be useful to you and others interested in this proposal in the meantime.

3 Likes