This follow up from a twitter discussion here https://twitter.com/softprops/status/1077533430924009473 I was directed here by @rustlang for a further discussion
While working on updating a crate to 2018 edition and removing extern crate usage, I discovered a weird quirk with custom derive name resolution that seems to conflict/cause confusion with typical trait name usage resolution.
This recipe that produces this conflict feels pretty common. I publish a crate called “foo” with a public trait called “Bar”. As a service, I publish another crate called “foo_derive” which is a proc macro crate that derives an implementations for “Bar” for the consumer crate types. Here’s the rub.
Since we no longer recommend #[macro_use] extern crate foo_derive;
The recommendation for consumers is to use standard use
statements in their stead. Using serde is a more canonical example it’s now recommended to use serde_derive::{Serialize, Deserialize};
instead of extern crate. On first glance this looks great. That is until, in the same consumer crate you need to invoke a method on an instance of the derived trait. At that point standard trait name resolution kicks in and users will have to use serde::{Serialize,Deserialize}
( or insert your trait here )
I’ve since learned that the serde crate has published a work around that avoids the UX issue by adding a feature flag to re-export the entire proc macro crates top level within the core serde crate.
With the scene’s characters set, what is the recommended script crate authors should follow (for now at least) to avoid having crate consumers having to both use foo::Bar
and use foo_derive::Bar
in the same lexical scope in order to achieve what we could in Rust 2015. Is the feature flag + re-export a recommended pattern? Whatever the recommendation is, I’d recommend promoting it strongly to ensure a consistent consumer experience for users pulling various trait deriving dependencies into their consumer crates.