<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Since people keep chiming in with “Rust has this”, I figured I should give the context for what’s up with Default in Rust. Disclaimer: I wasn’t around for the actual design of this API, but I worked with it a lot. So any justification I give is mostly my own posthoc perception of the purpose it serves today. I’ll also be using Swift terminology/syntax here since there’s no interesting aspect of Rust involved in this design.<div class=""><br class=""></div><div class="">There are three major use-cases for Default, as I see it:</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">1) providing conditional default initializers for generic types</div><div class="">2) providing a standard hook for easily writing “obvious” default initializers </div><div class="">3) refining another protocol for one-off convenience methods</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">The first case is easy. I have a `Mutex<T>`, `Box<T>`, `Rc<T>`, etc. Generic types which require an instance of their generic type to exist. So of course their initializer requires a T. But it would be nice to not have to do this for types which have default constructors. So you have `extension Mutex: Default where T: Default`, and now you can do `Mutex()` where inference makes it clear what the type is. </div><div class=""><br class=""></div><div class="">Here there’s no need to care about the “semantics” of Default. We’re just saying “if you can init() I can too!”. </div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">The second case is fairly Rust-specific, in that it combines with other features to make default initialization more ergonomic. Default provides a custom deriver, which makes a super convenient way to write default constructors for Plain Old Data types. #[derive(Default)] just says “yeah add a default initializer that loads up every field with its default”. Often this is done on a concrete type full of integers/optionals, in which case it’s synonymous with zeroing.</div><div class=""><br class=""></div><div class="">Since initializers in Swift are totally first-class, one could conceivably create this kind of Derive system without the need for protocols. Although #[derive(Default)] is generics-aware, so it can provide conditional conformances for generic types too.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">The third case is the most complex (and niche). In effect, there are several places where you can make a slightly more ergonomic thing if you refine a protocol with “has a default initializer”. These default initializers are in no sense a requirement of the protocol, so including the initializer as a requirement of the protocol is incorrect. At the same time, no one really wants a bunch of adhoc DefaultConstructibleX protocols that are used by maybe one or two functions in the entire world. </div><div class=""><div class=""><br class=""></div><div class="">So Default is used as a universal modifier that can be applied to any protocol to create DefaultConstructibleX without anyone having to actually define or know about it. It’s a kind of retroactive modelling. If your type has some kind of reasonable default value, you conform to Default and maybe someone uses it. A particular user of `X + Default` then infers <i class="">by example</i> what a reasonable Default would mean in this context. </div><div class=""><br class=""></div><div class="">Examples in Rust:</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">* H: BuildHasher + Default — Default applies the BuildHasher’s default seeding algorithm. For some algorithms this will go out to /dev/urandom, for others this will just set it to 0. That’s the call of the BuildHasher’s designer, and is hopefully made clear in its docs. However, there’s no reason why default constructibility is fundamental to a hashing algorithm. One could reasonably make the call that there isn’t a good default, and require it to be manually constructed. Possibly they could provide a couple wrappers which provide a clear default (MySecureHasher, MyWeakHasher).</div><div class=""><br class=""></div><div class="">This constraint is used by HashMap<K, V, H> ’s default constructor. So in a sense this is just a more complex version of the first case, but we’re definitely inferring some semantics here. If a Default implementation doesn’t exist, then one must use HashMap’s with_hasher constructor to provide an instance of BuildHasher. </div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">* R: Rng + Default — same basic idea. Default seeding strategy so you don’t have to pass an instance of Rng. No reason why all Rng’s must be default constructible.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">* T: Extend + Default — if something can be Extended and provides a default constructor, then presumably it’s some kind of collection. So default is presumed to be the empty collection. Again, Extend is more primitive then collections — one of the ends of a channel reasonably implements Extend, but default construction doesn’t make sense in that context. This is used by </div><div class=""><br class=""></div><div class="">partition<C>(predicate: (Item) -> Bool) -> (C, C)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>where C: Extend + Default</div><div class=""><br class=""></div><div class="">which is basically just:</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">var yes = C()</div><div class="">var no = C()</div><div class=""><br class=""></div><div class="">for x in self {</div><div class=""> if predicate(x) {</div><div class=""> yes.extend(x)</div><div class=""> } else {</div><div class=""> no.extend(x)</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">return (yes, no)</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">This is used similarly for unzip, which converts Iterator<(A, B)> to (CollectionOfA, CollectionOfB) </div><div class=""><br class=""></div><div class=""><br class=""></div></div><div class=""><br class=""></div><div class="">This case represents a situation where the Rust and Swift devs have diverged a bit philosophically. There’s a tendency in the Rust community to make small “lego” protocols which you snap together to get the semantics you want on the off chance there’s some weird type that doesn’t fit the mold. Swift tends to try to provide more fleshed out hierarchies. </div><div class=""><br class=""></div><div class="">This is partially influenced by the fact that fancy hierarchies are a lot easier to write and work with in Swift. Swift has much better support for retroactive modelling and crazy super-protocol-requirement-filling extensions. Defining things like Collection correctly in Rust has also generally been regarded as “needs some kind of higher kinded types” to handle the lifetime variables on Iterators.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">All in all, I don’t really have an opinion on whether Default makes sense for Swift. Haven’t thought about it all that much. Swift is still missing the features that make case 1 and 2 even viable motivations (conditional conformance and derive annotations), and I believe already mandates default initializers in several of the cases where 3 is relevant.</div><div class=""><br class=""></div></body></html>