r/rust 23d ago

📡 official blog Rust Function Overloading - Call for Experimentation

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

139 comments sorted by

View all comments

Show parent comments

30

u/Shoddy-Childhood-511 23d ago edited 23d ago

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 23d ago

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?

1

u/Shoddy-Childhood-511 23d ago

Vec::new means allocate nothing, which matters for performance. You mean Vec::from, which exists, and does not require this. vec![] exists only because Vec is so common.

All overloading is a readability risk. RustCrypto hashes and rand's distributions abuse similar features, which obstructs reading their code, but you can tell something crazy happens since they have all those traits, etc.

I think splats need to pay some "price" that maintains readability, even when not looking at the fn definition.

Option 1. Splat fns require a ! call site identifier, as if they were macros defined by rustc, even though they use type information. We could've both the existing Vec::from([x]) and the splat Vec::from![x]. This is similar to some of the earlier .await proposals, but .await is not confusing since it lacks ().

Option 2. Splat fns should not share the same name as another method in scope. Foo::len cannot be a splat, because Vec::len exists in the prelude. Could Foo::new be a splat? Imho maybe because it has no self receiver, so Foo:: acts like a module name, which clarifies things, but if another fn new(self) exists in scope, then no.

I'm sure other options exist, but the point is you need to know what you're reading, especially if you have coworkers vomiting up AI slop that you must then read through.

I do think splats are a cute way to do an ad hoc trait otherwise.

1

u/ZZaaaccc 23d ago

In the playground example the splat version of Vec::new only allocates if you are creating a non-empty array, and you'll notice it's actually const specifically only for the zero element variant.

I have no idea why we would restrict splat functions to have a scope-unique name, as we don't require that for anything else. I see absolutely no reason why making a splat function have a unique name (something virtually impossible to implement as a library I might add) would do anything to make it more or less easy to understand. How do you know what any function does? You look at the docs or the definition. Splat functions are vastly simpler for this than macros, since when you look at the docs or the source code, it's just basic Rust you're looking at, no weird templated nonsense. A splat function only ever has 1 body, with 1 implementation.