---
We could add implicit enums to impl Trait, so that you could return different types from a function:
fn foo() -> enum impl Display {
if rand() > 0.5 {
"str"
} else {
42
}
}
which would let you get around the problem of returning a type erased object for a Trait that isn't object safe: trait Trait {
const C: i32 = 0;
}
impl Trait for i32 {}
impl Trait for &'static str {}
fn foo() -> Box<dyn Trait> {
if true {
Box::new("")
} else {
Box::new(42)
}
}
error[E0038]: the trait `Trait` cannot be made into an object
--> f500.rs:6:17
|
6 | fn foo() -> Box<dyn Trait> {
| ^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> f500.rs:2:11
|
1 | trait Trait {
| ----- this trait cannot be made into an object...
2 | const C: i32 = 0;
| ^ ...because it contains this associated `const`
= help: consider moving `C` to another trait
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead:
&'static str
i32
---Relax object safety rules, like making all assoc consts implicitly `where Self: Sized`.
---
We could make enum variants types on their own right, allowing you to write
fn foo() -> Result<i32, i32>::Ok { Ok(42) }
let Ok(val) = foo();
There's some work on this, under the umbrella of "patterns in types". For now the only supported part of it is specifying a value range for integers, but will likely grow to support arbitrary patterns.---
Having a way to express `impl Trait for Enum {}` when every `Enum` variant already implement `Trait` without having to write the whole `impl`.
---
Anonymous enums:
fn foo() -> Foo | Bar | Baz
---Being able to match on Box<dyn Any> or anonymous enums
match foo() {
x: Foo => ...,
x: Bar => ...,
_ => ...,
}
---Stop needing to create a new struct type in order to box a single variant
enum Foo {
Bar(Box<struct { a: i32, b: i32 }>),
}
---These are of the top of my head, there are many things that you can do to make trait objects and enums feel closer than they do today, to make changing the way your code works a "gradient" instead of a "jump". My go-to example for this is: if you have a type where every field is Debug, you can derive it. As soon as you add one field that isn't Debug, you have to implement the whole impl for your type. That's a "jump". If we had default values for structs you could still use the derive by specifying a default value in the definition. That makes the syntactic change "distance" be as far as the conceptual change "distance".