Edit: playground codes revised after initial post.
Edit: Problem title edited.
The biggest stopper for me was the problem described below. Edit: but the entire problem space is too big and I can’t write actual RFC for the time being.
Problem: Adding type parameter with default type is not sufficiently backward-compatible
The biggest problem I've encountered is backward compatibility of added type parameter.
Generally adding default type parameter is considered 'compatible' but it isn't really.
Suppose you have struct DataStructure<T>
and wrote some code:
let data = DataStructure::from(vec![0, 1, 2]);
println!("{:?}", data);
Then you extended your struct with second type parameter with default argument:
pub struct DataStructure<T, S = DefaultStrategy>
where S: Strategy
{ ... }
Looks nice, but unfortunately it won't compile old codes without added annotation:
Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed for `DataStructure<i32, S>`
--> src/main.rs:24:16
|
24 | let data = DataStructure::from(vec![0, 1, 2]);
| ---- ^^^^^^^^^^^^^^^^^^^ cannot infer type for `S`
| |
| consider giving `data` the explicit type `DataStructure<i32, S>`, where the type parameter `S` is specified
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=368afa8860349e6bd2c59575a9fa8c04
It’s ridiculous because I supplied default type to S.
Possible solutions
(A) 'Fix' compiler to infer the type 'correctly'
I don't know whether it's feasible.
(B) use (ugly) type alias.
Rename the original struct, and provide alias to the old name:
pub type DataStructure<T> = DataStructureWithStrategy<T, DefaultStrategy>;
pub struct DataStructureWithStrategy<T, S> { ... }
Old code and new code both compile, but code becomes ugly:
// old code compiles!
let data = DataStructure::from(vec![0, 1, 2]);
println!("{:?}", data);
// new code looks ugly... :-(
let data: DataStructureWithStrategy<_, DefaultStrategy> = DataStructureWithStrategy::from(vec![0, 1, 2]);
println!("{:?}", data);
let data: DataStructureWithStrategy<_, SuperStrategy1> = DataStructureWithStrategy::from(vec![0, 1, 2]);
println!("{:?}", data);
let data: DataStructureWithStrategy<_, SuperStrategy2> = DataStructureWithStrategy::from(vec![0, 1, 2]);
println!("{:?}", data);
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fb82901dde2616b7108f809978630d3f