Pre-RFC: Named arguments

It's not just related, it's isomorphic. It's exactly the same operation!

Look:

//  This is evil because "overloading"


fn print(x: i32) { unimplemented!(); }
fn print(x: String) { unimplemented!(); }
fn print(x: i32, y: String) { print(x); print(y) }

fn main() {
    let i = 1i32;
    let s = "salmon".to_string();
    
    // Same method name, postfix arg(s)
    print(i);
    print(s);
    print(i, s);
}

vs.

// This is brilliant because it's overloading BUT args appear on the LEFT!
// Or because it has tons of boilerplate that surely clarifies things?

struct NewI32(i32);
impl NewI32 {
    fn print(self) { unimplemented!(); }
}

struct NewString(String);
impl NewString {
    fn print(self) { unimplemented!(); }
}

struct NewBoth((i32, String));
impl NewBoth {
    fn print(self) {
        let NewBoth((i, s)) = self;
        NewI32(i).print();
        NewString(s).print();
    }
}

fn main() {
    let i = NewI32(1i32);
    let s = NewString("salmon".to_string());
    let is = NewBoth((2i32, "cod".to_string()));
    
    // Same method names, prefix arg
    i.print();
    s.print();
    is.print();
}

There's no ad-hoc polymorphism, no dynamic dispatch. It's all static dispatch both ways, except one way is a truckload of work to do on purpose (but happens inadvertently all the time as people create libraries and use the same names), and the other way is maligned because...doing it on purpose is worse than doing it by accident?

Java (and C++ and Scala and...) also dispatches statically to overloaded methods based on the static type of the arguments. (Clojure's multimethods and Julia's multiple dispatch do pick based on dynamic type. That is ad-hoc polymorphism. Plus lots of languages have ordinary polymorphism on the first argument of the function--but again this is a different kettle of fish.)

So, anyway, Rust totally has overloading (but only for the prefix argument).

4 Likes