There is a strong commitment for Rust not to break backwards compatibility, meaning that all code that compiled with Rust v1.0 should compile with all future Rust versions, all but for exceptional circumstances. The effort is commendable, and results in kool things like Editions, but mistakes are bound to happen that cannot be fixed with such. That is, I wish we will have a breaking release at some point, and the pain of such a breaking change could be relieved/eliminated with careful planning and migration tooling.
That said, following are my favorite breaking things I want in Rust (and many are much too outrageous to ever be seriously considered).
lang
-
Assigning values to struct bindings should use the equal sign, not the colon:
// now Shoe { size: 10, style: "sneaker" }; // dream Shoe { size = 10, style = "sneaker" };
This would be consistent with the rest of the language.
-
It would be nice to make the language a little smaller by unifying syntax for functions and closures (inspiration).
A closure syntax looks like this:
fn main() { let square = |number: i32| { number * number }; println!("{}", square(4)); }
A function for same looks like this:
fn square(number: i32) -> i32 { number * number } fn main() { println!("{}", square(4)); }
Imagine if you could have this instead:
let square: |number: i32| -> i32 = { number * number } fn main() { println!("{}", square(4)); }
It is a bit more heavy on tokens (there is an extra
:
and there is a=
), but it also means one less keyword (fn
), and less syntax to learn for new users.As an additional example, this is what a function would look like if it returned nothing:
let show_square: |number: i32| = { println!("{}", number * number); } fn main() { show_square(4); }
As a final note on this one, this is what an async function would look like (inspiration):
let show_square: |number: i32| -> i32 = async { ... }
-
Perhaps ridiculous, but what if we got rid of
struct
andenum
keywords, where the structure of the types is instead inferred:// current struct Character { name: String, kind: Kind, } enum Kind { Good, Bad, Ugly(Detail), } struct Detail; // wish type Character = { name: String, kind: Kind, } type Kind = { Good, Bad, Ugly(Detail), // looks like a struct with an unnamed field } type Detail; // implicitly a struct type StructWithUnnamedFields(String, Kind); // and unions are a special case, so we use this new syntax... type SomeUnion = union { integer: u32, float: f32, }
This brings the syntax close to type aliases.
-
Replace underscores (_) with dashes (-) in bindings/identifers:
// current let we_dream; // wish let we-dream;
That is a lot more pretty, but would disallow math operations without spaces, like
one-number - another-number
.
std
-
All collections types removed, except these basic ones: Vec, HashMap, and HashSet. Also, they would also be available from top-level (i.e.
std::{Vec, HashMap, HashSet}
), resulting instd::collections
removal. -
Rename
Vec
toArray
, a more clear/obvious name. An alternative isList
, but that type in Python accepts members of different types, which is not the case forVec
. -
Consistent names for string-y types:
current wish string str Str String StrOwned os string OsStr OsStr (same) OsString OsStrOwned C string CStr CStr (same) CString CStrOwned fs path Path Path (same) PathBuf PathOwned -
Remove
std::sync::mpsc
from stdlib, making it available externally... it does not feel general enough. (more issues) -
Remove per-type methods where trait impls offer same functionality, for generality:
current wish PathBuf::as_path PathBuf::as_ref Path::to_path_buf Path::to_owned Vec::append Vec::extend -
Remove all deprecated APIs, most notable being the
try!
macro -
Renames of panic methods (inspiration)
current wish foo.unwrap (remove) foo.expect("message") foo.or_panic("message") foo.unwrap_or foo.or foo.unwrap_or_default foo.or_default foo.unwrap_or_else foo.or_else It feels somewhat implicit, but maybe not so bad.
cargo
-
Do not allow crate names with underscores, because taste...
serde_json
(bad)serde-json
(good)