Isn't struct Length(u8) already the de-facto standard for newtype, just that it can require a lot more typing in the derive? Imagine we had a way to "bundle" multiple derives together (I'm not speaking of a derive macro here):
// Or some other syntax, this one potentially even as part of the prelude
// if newtypes are common enough
type NewType = Debug + From + ...;
type Math = Add + Sub + Mul + ...;
// Ideally allow anyone to specify Derive (and trait bound?) collections/bundles,
// Would likely need a different syntax.
type Common = Debug + serde::Serialize + serde::Deserialize;
#[derive(NewType, Math)]
struct Length(u8);
// No Math because it has a different return type
#[derive(NewType)]
struct Instant(u64);
#[derive(Common)]
struct Length{...};
Yes, it's still more than newtype Length = u8, but it's also more flexible and allows specifying what exactly you need.
As for the above mentioned trait bounds: Imagine serde having this:
// In serde (may need to be split between Trait bundle/alias and
// Derive bundle/alias)
type Serde = Serialize + Deserialize;
// In crates using serde
#[derive(Serde)]
struct MyStruct{...}
fn do_something(T: Serde) {...}
Or tokio this:
type Task = Send + Sync + 'static;
// Simplified
pub fn spawn<T: Task>(task: T) {...}
Unless I'm mistaken, this currently requires a third trait with auto-impls if both Serialize and Deserialize are present and would require another proc macro for derive.