Workaround for lack of negative trait bounds?

Hello,

I have a generic type, and I would like to be able to use any numeric type; whether signed or unsigned, fixed or floating point.

But if the type is signed, I need to be able to calculate an absolute value using the appropriate function. If the type is bounded by num_types::Signed then it will implement abs() But if not, I'd like to supply an abs() function that is just a no-op.

If I could used "negative trait bounds", I might do it like this:

impl <T : !Signed> ODCPoint for T {
    fn abs(self) -> Self {
        self
    }
}

But I've read the discussion about why negative trait bounds is a can of worms in general.

Have any of you run into something like this? What's the best solution you have found?

Thank you.

You are going to need to have a single trait that provides an abs function for both kinds of integers.

1 Like

Rats. I thought I'd try this:

trait ODCPointWithAbs {
    fn abs(&self) -> Self;
}

impl <T : ODCPoint + Unsigned> ODCPointWithAbs for T {
    fn abs(&self) -> Self {
        self
    }
}

impl <T : ODCPoint + Signed> ODCPointWithAbs for T {
    fn abs(&self) -> Self {
        Signed::abs(self)
    }
}    

But the compiler doesn't seem to know Signed and Unsigned are exclusive of eachother.

One thing you can often try is to blanket impl abs in the following way:

let zero = ...;
if a < zero {
    zero - a
} else {
    a
}

Interesting. I was hoping for a compile-time solution vs. a runtime solution. But your proposal would totally work. :slight_smile:

I think in practice, I'll just provide implementations for all of the numeric primitives, and allow the crate user to provide their own implementation if not. I was just hoping to shield the user from the extra complexity.

Thanks for the replies!

At least for the ordinary integers, my solution would compile down to the usual abs function. But of course bigints may have much more efficient implementations for abs.

I thought of the same thing, but beware of panics due to subtracting with overflow on debug. (It behaves like Signed::abs on release: ${SignedInteger}::MIN returns itself, even though it's negative.)

Didn't think of that! Signed integer types have 1 extra value of negative range vs. positive range. :man_facepalming:

I guess it will require an additional check for that case.

Thanks!