Deriving for tuple structs


#1

Creation of new numeric types seems to be a common pattern (I mean types that behave like numbers, but can’t be accidentally confused with other integer or float types, e.g. Centimeters/Inches/ Celcius/Farenheit).

The problem is that creation of such type using a tuple struct (struct SomeUnit(f64)) requires boilerplate implementation of all basic numeric traits such as Add, Sub, Mul, (Partial)Ord, (Partial)Eq, etc.

A typical solution is to use a macro to generate trait implementations… but Rust already has feature for deriving “boring” implementations!

Therefore I suggest supporting #[derive(Add, Sub, Mul, Div, PartialEq, PartialOrd)] (etc.) for tuple structs.

The behavior could be: When derive is used, if the first (the only?) element of the tuple struct supports the trait, then implement that trait using the first element’s implementation.


#2

I think you are overestimating what derive is capable of. Sofar as I know, it doesn’t have any access to type information at all; it’s just like a macro.

Besides, who needs compiler support when you have a deranged madman at hand?

#[macro_use] extern crate custom_derive;
#[macro_use] extern crate newtype_derive;

custom_derive! {
    #[derive(Copy, Clone, Eq, PartialEq, Debug,
        NewtypeAdd, NewtypeAdd(ref),
        NewtypeBitAnd, NewtypeBitAnd(ref),
        NewtypeBitOr, NewtypeBitOr(ref),
        NewtypeBitXor, NewtypeBitXor(ref),
        NewtypeDiv, NewtypeDiv(ref),
        NewtypeMul, NewtypeMul(ref),
        NewtypeRem, NewtypeRem(ref),
        NewtypeSub, NewtypeSub(ref),
        NewtypeFrom)]
    pub struct Wrapper(i32);
}

// Wrapper now has all those arithmetic ops, plus two-way
// From impls.

(custom_derive is up on crates.io, but you’ll have to grab newtype_derive from Github as it’s still a WIP.)

Edit: I should probably note that the above doesn’t work if you try to derive all arithmetic operators for all existing overloads… you kinda crash face-first into the macro recursion limit. -cough- I might be pushing macro_rules! a bit outside of its comfort zone… into a pit of rabid wolves. That are on fire. And when they bark they shoot bees. Which are also on fire.


#3

It’s a testament to macro-rules’ resilience that it fights against flaming rabid wolves that shoot fiery bees and the only thing that can stop it is the macro recursion limit.


#4

That might still work — it could blindly create Add implementation based on these assumptions, and later the compiler would protest if the macro-generated code doesn’t compile due to lack of the Add trait.


#5

Note that you can lift the recursion limit by adding:

#![recursion_limit = "1024"] // or some other big number

at the top of your crate.


#6

Indeed, deriving has no type information. But we could certainly add “dumb” deriving forms that just try to add all fields (just as eq tries to compare all fields). This would work for a lot of simple stuff (in particular for new types).

Still, the plan all along has been to ultimately move deriving out of the compiler. Your macro rules version is pretty nifty. I’ve been wanting to make #[] attributes an alternative way to invoke macros, as well, which would make it even more nifty.


#7

Except that (IIRC) requires a nightly compiler, at which point I might as well just surrender to inevitability and write a syntax extension.

Then I wouldn’t need custom_derive!. Actually, the secret plan all along has been to try and prove that you can implement various deriving forms using macro_rules! to try and provide motivation for “official” support.

Another goal is to try and highlight where changes to macro_rules! would be most useful. Currently, #1 is a lifetime matcher, followed by some kind of tail recursion (so tt munchers don’t trivially blow through the stable limit).

Oh, and eager expansion. And a simple token-based eval!. And bang! thump


#8

I don’t think it does, actually.


#9

You appear to be correct. Damn. Now I’m going to have to go adjust the documentation on custom_derive!