Posted on ::

(see Rust std dreams for a similar list, but for the standard library)

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 the Rust language (and many are much too outrageous to ever be seriously considered).

  • 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 and enum 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 arithmetic operations without spaces, (since - is a subtraction symbol).

  • Remove re-exports (inspiration)

    This would make it more clear where functionality comes from. Not sure the convenience of not having to explicitly manage a dependency is worth the feature.

  • Replace && || with and or, for less visual noise (like Python)

  • Replace *some_ref with some_ref*, to ease reading of nested dereferencing (source).

    // current
    *(*(*pointer).field).complex_method()
    
    // wish
    pointer*.field*.complex_method()*