uom icon indicating copy to clipboard operation
uom copied to clipboard

Use mathematical fn on generic quantity

Open T-Bakker opened this issue 3 years ago • 4 comments

Hi,

I am trying to use uom quantities in a generic context. More specifically, I am trying to use mathematical functions such as abs, ceil, floor, signum, etc on these generic quantities.

I have a function that applies kinematics on a quantity. This quantity can be a Length or a Angle quantity:

fn complex_kinematics_things<S>(input: S) -> S
where S: std::ops::Add<Output = S> + std::ops::Sub<Output = S> + PartialOrd + Copy + num_traits::identities::Zero {
    if input.signum() < S::zero() {
        // do something
    } else {
        // do something else
    }
}

However, I am unable to call signum on type S as it is a generic and the function is defined on the struct itself: https://github.com/iliekturtles/uom/blob/e943f8cb411ef8ab461df794b57dc841a68970c5/src/system.rs#L738-L748 Therefore, there is no way for me to specify that the generic has a signum. If however the quantity would implement the num_traits::sign::Signed trait, I could specify that trait bound for my generic function.

Would it be possible to modify uom to define the signum function (and others) not on the struct, but instead implement the corresponding num trait? For example:

impl<D, U, V> num_traits::sign::Signed for Quantity<D, U, V>
where
    D: Dimension + ?Sized,
    U: Units<V> + ?Sized,
    V: $crate::sign::Sign + $crate::Conversion<V>,
{
    #[inline(always)]
    fn signum(self) -> Self {
        Quantity {
            dimension: $crate::lib::marker::PhantomData,
            units: $crate::lib::marker::PhantomData,
            value: self.value.signum(),
        }
    }

    // <Insert other fn of Sign here>
}

See also my playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=afacf8c47d6570e864dcd3f3f477f4ce

Thanks in advance! Tommas

T-Bakker avatar Sep 28 '21 10:09 T-Bakker

Good suggestion. I'm going to clarify the subject. We'll also want to take a look at any other traits similar traits that could be implemented.

iliekturtles avatar Sep 28 '21 19:09 iliekturtles

Started looking at this and it isn't possible to implement Signed currently. Signed inherits Num which in turn inherits NumOps which in turn inherits Mul<Rhs, Output = Output>. uom's quantity can't implement Mul<Rhs, Output = Output> because the multiplication of two quantities is a different quantity. e.g. length * length = area, not length.

I'm going to leave the issue open for a bit longer to think on it, but we may be stuck unless the trait definition changes.

iliekturtles avatar Oct 01 '21 14:10 iliekturtles

Hi,

Thank you for looking in to it. I did not investigate that far. The numtraits are indeed to restrictive in that sense. Ideally, numtraits would be modified to allow for this scenario. However, I do not think that is very likely to occur.

Perhaps a second option/plan B is to define the traits in the uom library itself. Although I think this is way less elegant than using the numtraits, it does allow the functions to be used in a generic context.

Thank you for your investigation! Tommas

T-Bakker avatar Oct 03 '21 21:10 T-Bakker

For your fn complex_kinematics_things<S> is the S parameter always a quantity (e.g. Length, Time, Velocity, ...) or completely different types (e.g. Length, f32, )? If you're always using quantities then you can adjust your generic parameter / function parameter to accept any quantity.

iliekturtles avatar Oct 04 '21 23:10 iliekturtles