Deriving numeric functionality for generic newtype

Say I have a newtype that I want to be generic over f32 and f64. To express this, I use num_traits::Float, like so:

use num_traits::Float;

struct Foo<T: Float>(T);

I would like to implement Float for Foo also. Most obvious is num_derive::Float, but that seems to fail for generics. The following does not compile due to a lacking generic parameter, suggesting to use Foo<T><T: Float>(T).

use num_traits::Float;

struct Foo<T: Float>(T);

(I would post a playground link, but num-traits is not included.) Indeed, there is an open issue that appears to confirm that this is not possible in num-derive.

The very helpful derive-more crate does support derives for generic newtypes, though, and so I figured that if I can auto-derive all the common operators, then I can manually implement the rest of the num-specific traits without too much hassle, maybe using some delegation crate to cut down on boilerplate. The following compiles and seems to work:

use derive_more::{Add, AddAssign};

use num_traits::Float;

#[derive(Add, AddAssign)] // And so on for the remaining operators...
struct Foo<T: Float>(T);

As far as I understand, however, derive_more only helps me with Foo + Foo, but cannot derive Foo + &Foo, &Foo + Foo, or &Foo + &Foo, though it's very possible I'm missing some functionality in derive-more?

A couple of crates exist to derive operators for the various combinations of owned and borrowed values, but none of them appear to work for generic newtypes. These include newtype_derive and impl_ops (apparently succeeded by auto_ops).

My question, therefore, is how best to solve this problem? I'd rather avoid writing a tremendous amount of error-prone boilerplate for all the operations. I'm thinking I could probably solve this with macro_rules, but I'm unfamiliar enough with macros for this to feel somewhat daunting, and I feels like a common enough problem that someone else must've come up with a good solution?

It looks like the approach in this num-derive pull request would work in your case, though it fails in some more complex cases. Maybe @cuviper would be willing to merge something based on that, even though it isn't flexible enough to cover all use cases?

Just yesterday, I implemented Float by hand for a wrapper type, using some complicated find-and-replace patterns to generate the boilerplate. It is... not ideal.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.