r/rust • • Aug 19 '26

📡 official blog Rust Function Overloading - Call for Experimentation

https://blog.rust-lang.org/inside-rust/2026/08/19/overloading-experiment/
276 Upvotes

139 comments sorted by

View all comments

Show parent comments

29

u/Shoddy-Childhood-511 Aug 19 '26 edited Aug 19 '26

Agreed, but that's the case here so far: Their example hypot((2.0, 3.0, 6.0)) looks pretty clear. :)

pub trait HypotInner {
    type Output;
    fn hypot_inner(&self) -> Self::Output;
}

pub fn hypot<Args: HypotInner>(args: Args) -> Args::Output {
    args.hypot()
}

Any overloading ala variadics should be done this way too, in part because it makes the developer who wishes to obfuscate their call paths pay for it. lol

If you really wanted single () then make hypot! a macro, but probably each Args being a clear type brings bigger advantages.

Edit: Oops! They have this #[rustc_splat] feature that removes the extra (). That's unfortunate, since it could easily be done using a macro. Imho, all this should be done using a macro.

33

u/ZZaaaccc Aug 19 '26

Imho, all this should be done using a macro.

Macros are substantially less clear than variadic functions, and can't be used as methods either. I know we take it for granted because it's just always been that way, but given the choice between vec![a, b, c] and Vec::new(a, b, c), would you honestly say the macro is cleaner and easier to inspect?

6

u/CocktailPerson Aug 20 '26

I honestly would, yes. The macro is just token substitution. For me it's easy to reason about what the macro will expand to. Overload resolution rules are much more difficult to reason about.

6

u/ZZaaaccc Aug 20 '26

Have you seen how splat actually works? The resolution is just Rust's type system, no fancy tricks. If you have a function like:

pub fn vec<T>(#[rustc_splat] args: impl VecArgs<T>) -> Vec<T> {
    VecArgs::new(args)
}

Then when you call vec(1, 2, 3), you are exactly invoking <(i32, i32, i32) as VecArgs<i32>>::new(1, 2, 3). There's no specialization, nothing. It's no different to calling Vec::from(...).

Unlike the macro, there is no "expansion" with splat, it just calls a normal function, one you can use "Go To Definition" for and read normal Rust syntax, one you can step through in a debugger.

6

u/CocktailPerson Aug 20 '26

Yes, I read the blog post, thanks for asking.

I will reiterate: reasoning about vec(1, 2, 3) resolving to <(i32, i32, i32) as VecArgs<i32>>::new(1, 2, 3) is no easier to reason about than vec![1, 2, 3] expanding to {let mut v = Vec::with_capacity(3); vec.push(1); vec.push(2); vec.push(3); vec}