Marker trait bounds: Into<u32> works but can't get u32: From<T> to compile

As a learning experiment, I'm trying to implement a marker trait[1] that will allow me to see if I can solve a codewars challenge with u8 or u16 as opposed to u32; my goal is to get a working implementation with u32 and then try smaller types to see if I get an overflow. I have a number of traits that the type will need to implement, but I think my first roadblock is figuring out why I can't get a u32: From<T> bound[2] to work on my trait.

I think this example code illustrates the issue; in essence the below trait works fine:

trait IntoU32: Into<u32> {}
impl <T>IntoU32 for T where T: Into<u32> {}

whereas this trait doesn't work at all:

// At some point the compiler wanted `Sized`
trait TFromU32: Sized where u32: From<Self> {}
impl <T: Sized>TFromU32 for T where u32: From<T> {}

It seems like there should be a way to have a trait that restricts (and blanket implements) where u32: From<T>. Is there? As there aren't any generics in the trait definition (to permit From<T>) I hoped From<Self> might be the way to do this. It seems not.

  1. If I'm using terms improperly I'd appreciate some feedback ↩︎

  2. I need to perform a .pow operation which requires a u32 ↩︎

You can use a constraint like u32: From<T> in general, but it won't be elaborated when you use a trait on T -- see:

1 Like

Related: Trait that automatically implies several From implementations? - #11 by jbe

1 Like

This compiles, but I kinda don't see the point – why don't you just use where u32: From<T> alone in the first place?

Was just perusing that issue when you commented -- thanks!

So looks like where T: Into<u32> works but where u32: From<T> doesn't because... why again? Does elaborated mean that the compiler is creating the "requested" implementation for the generic?

The actual trait in question depends on 10 or so trait constraints (and is in effect fairly similar to the num_traits crate); I'm hoping to write a "convenience trait" that allows me to implement a dozen or so functions for types that fulfill that trait (instead of having to maintain the constraints individually on each function, which is why I didn't want to do u32: From<T> on each function).

It is running in a context that disallows external crates, and I'm interested in learning how one would go about creating such a "convenience trait".

As I loosely understand it, elaborating happens when you write where T: IntoU32, then it also lets you use the supertrait as if you had written where T: IntoU32 + Into<u32>. This doesn't happen for indirect where clauses on the trait -- where T: FromU32 doesn't have anything else to add about T, but it would be nice if that also implied the u32 constraint for you.

1 Like

So sounds like that is probably it: trait ...: Trait just works differently than trait ... where type: Trait

And T: From<U> creates a reciprocal Into, but unfortunately it doesn't work the other direction. So I guess I'll just change from From to Into and change all my u32::from calls into an .into.

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.