|
|
Log in / Subscribe / Register

Never traits

Never traits

Posted Sep 11, 2026 4:16 UTC (Fri) by tsavola (subscriber, #37605)
Parent article: Stabilizing Rust's never type

After this change (and on the 2024 edition), the compiler assumes that T should be !, which doesn't implement Default, and therefore causes a compilation error.

Couldn't ! just be assumed to implement any and all traits?


to post comments

Never traits

Posted Sep 11, 2026 5:39 UTC (Fri) by micka (subscriber, #38720) [Link] (3 responses)

For Default, you need to provide one value, and you can’t do that for !.

Never traits

Posted Sep 11, 2026 5:50 UTC (Fri) by tsavola (subscriber, #37605) [Link] (2 responses)

Yes, but with ! that code path is never reached. The compiler could say that it can, because it never has to.

Never traits

Posted Sep 11, 2026 6:57 UTC (Fri) by taladar (subscriber, #68407) [Link] (1 responses)

But that is not how traits work in Rust. What you suggest would be true if all traits just had their types appear in parameter position in the methods they implement but traits like Default have them appear only in return type position where you absolutely have to come up with a value if someone calls <! as Default>::default()

Never traits

Posted Sep 11, 2026 7:17 UTC (Fri) by tsavola (subscriber, #37605) [Link]

Okay, I see.

Never traits

Posted Sep 12, 2026 7:52 UTC (Sat) by NYKevin (subscriber, #129325) [Link]

Sort of, but not exactly. I believe this confusion arises from conflating traits with types.

Instances of ! can be coerced into arbitrary types. So if you're coming from another language, it might seem intuitive to assume that this means ! should implement all traits. But it is important to remember that traits are not types.

If types are nouns, traits are adjectives. Or to put it another way, a trait specifies a family or category of types, not a type in its own right. This differs significantly from interfaces in languages that support them (Go, Java, etc.), where you can simply treat an interface as if it is a type for all purposes (except for calling the nonexistent constructor). You can turn a trait into a type by prefixing it with the keywords dyn or impl, but those are not the same as the trait itself, and have important differences in their semantics:

* dyn Trait is only compatible with some traits. It is also dynamically sized and must exist behind a pointer, in a language with manual memory management and no GC. Either of those restrictions in isolation would be far too annoying for dyn Trait to be the type-level equivalent of Trait (but early Rust did try to make this work). This also implies the use of a vtable for dynamic dispatch (hence the name "dyn"), and the incompatibility stems from methods that do things like passing Self by value, not having a receiver at all, having type parameters, etc. (none of which can be dynamically dispatched in Rust).
* impl Trait is compatible with all traits, but it's a form of generics. Generics must be tied to some function or other context that tells the compiler how they should be monomorphized. So you can't treat it as a general-purpose type-level equivalent of Trait, because in non-generic contexts, this would make no sense. In a generic context, impl Trait should be read as "some type which implements Trait, but I'm not going to tell you what type it is."

The Default trait, in particular, is the Rust equivalent of what C++ calls "having a default constructor." It is not a type, nor does it have a type-level equivalent in most languages.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds