Allow derive macro, trait and types with the same name

More often than not I encounter errors like expected trait, found derive macro X or expected type but found trait and so on which requires an explicit import. As far as I know Rust expects only a single one of these in a given context and there's nothing to disambiguate, so I think the restriction on same-name trait and types seems to be arbitrary.

For example with this the prelude could include both Hash trait and the derive macro and still remain backward compatible. Same goes for traits and types where you don't have to invent a new name if you start with a trait and then a structure to implement it, they could simply use the same name.

It’s worth mentioning that in edition 2015 and 2018, every trait also defines a type, the type of “trait objects”. The dyn keyword introduced with rustc version 1.26 made the situation more explicit so you can nowadays write &dyn Any instead of &mut dyn Write etc… instead of &Any, &mut Write etc. Rust 2015 and 2018 editions are however still supported of course; and API interfaces are supposed to work well across editions.[1]

Also, there’s an argument to be had, on the same grounds that motivated trait object types no longer have the same name as the corresponding trait, that instead allowing an arbitrary pair of type & trait to share the same name can be equally – or maybe even more – confusing.


Derive macros on the other hand are already supported to co-exist under the same name as a trait[2], and very often do.

I’m not completely sure where to find any existing discussion about the question of including the Hash trait in the prelude, but I don’t think there’s any technical argument against such a step; especially I can hardly imagine any backwards-compatibility-related reasons that would be alleviated by any more forgiving rules on types and/or traits and/or macros with the same name. Feel free to be more explicit about what exactly you had in mind here though :wink:[3]


  1. Technically, there are ways around this, like one could make some re-export visibility dependent on the edition of the importing code… it may get annoying to use though. Also, probably the question more prominently arises of how to import only the trait or only the type of a certain name, if a user wants to do that. ↩︎

  2. or a type ↩︎

  3. One reason that I can imagine is that “Hash” is such a generic name that we’d want to allow users to make use of it for their own types and/or traits more easily.

    And conversely, the reason for the derive to be in the prelude is most likely entirely historic, from a time when these derive macros were magical compiler-builtins that were always in scope by default, anyway, and users could not even define their own ones to begin with. [You can see this RFC happened after Rust 1.0, but Rust 1.0 does already support #⁠[derive(Hash)].] ↩︎

3 Likes

I'm opposed to this, both because it could be confusing, and because it places constraints on the syntax for future language extensions. Rust currently uses : to mean all of "has type", "implements trait", or "outlives", which means that if you have a context in which you want to be able to say either of "this value has this type" or "this type implements this trait", the two have the same syntax (and although there are no such contexts at the moment, it seems plausible that some might be added). This currently would be unambiguous specifically because type and trait names can't be the same (except in the dyn Trait case, which can be spelled as Trait in Rust 2015 despite being a type, and this usually isn't a problem due to dyn Trait being unsized).

In retrospect it would probably have been better to use different punctuation for the "type implements trait" and "value has type" syntaxes, but it's probably too late to change now.

1 Like

“The first rule of computer language design is that everybody wants the colon” — Larry Wall

It’s such a handy character for “there is some kind of relationship between these two things”, and it’s out of fashion to put an actual verb instead of punctuation in there instead.

5 Likes

If we're feeling particularly adventurous, the Unicode Confusables page has plenty of doppelgängers to choose from:

(</s>)

2 Likes