Could we have `std::default()`?

either

#[inline(always)] fn default<T: Default> () -> T { T::default() }

or

macro_rules! default { () => ( Default::default() ) }

I think I like the latter most since the macro exclamation mark reminds that it’s just a shortcut.

Not sure if something that short should be in the std prelude, since you can use a custom prelude crate like the aforementioned default or even define that one liner at the beginning of your project (I very often have a private utils module in my projects with its namespace “inlined”: use crate::utils::*;)

Please please please don't use always unless it's necessary (you're doing evil things where an extra stack frame would break it, for example).

Just #[inline] is plenty for things like this; using always just forces things where they shouldn't, making binaries bigger and compile times longer. (And because it's a generic, it'll almost certainly get inlined even without any attribute, in this case.)

An example that was just mentioned in LLVM weekly: [cfe-dev] libc++ is not using always_inline anymore!

4 Likes

The post talked about aliasing ::std::default::Default::default as default, similar to a use SomeEnum::SomeVariant;. The closer to aliasing you can currently do in this case is redefine a dummy wrapper function; which ceases to be a dummy function and becomes a true 0-cost alias thanks to the #[inline(always)].

You are right that many people overuse the #[inline(always)] attribute; but in an aliased function scenario it is the right thing to do. Without it, either the compiler finds out by itself that the function must be inlined since it’s just an alias (in which case adding the attribute is a no-op), or for some obscure reason the compiler does not inline it (increasing the binary size!), adding one layer of call indirection. This hurts not only because of the extra "jump to T::default" but also because of the "return from T::default" (no tail-call optimization as of yet).

4 Likes

Rust does have RVO, so retuning any value directly costs nothing.

2 Likes

No, it's really not. #[inline] is plenty. LLVM is very aware that for something that trivial it's always profitable. Using always just makes debug builds slower; it doesn't ever help release builds.

Instead of a default function I wonder if can’t get lightweight syntax support for filling default. eg:

let mystruct = MyStruct {
  x: 42,
  y: 23,
  ..
}

Which would automatically fill from Default.

1 Like

I don’t like the idea of making Default special/built-in… from a “purity” point of view, I think most things should just be built on generic/general purpose language features.

Your proposal is similar to: Pre-RFC: Partial Initialization and Write Pointers

You can already do this if MyStruct: Default, with a little extra syntax. (this is called FRU, Functional Record Update) playground

let mystruct = MyStruct {
  x: 42,
  y: 23,
  ..Default::default()
}
1 Like

No, I don’t think so, @mitsuhiko wants a complete value at the end, which is the opposite of what PITs are supposed to do. FRUs seem to be more inline with what he wants.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.