Trait bounds vs trait objects as references in structs

Hi there.

As part of learning rust I have been writing a small image library, and I would like to ask help with a feature I'd like to implement where I can isolate the different color channels and treat each channel as though it were an image of the sub pixel type.

The code below is a small simplified part of the larger thing I'm working on.

In this case Red is a struct that represent the red channel of an image.
I implement the Image trait for that struct so I can treat Red like any image where the pixel of that image is just the sub pixel type.

The issue I have is the only way that I have managed to do this is using a trait object reference to the owner of the pixel data.
In some ways I prefer this because if I were using generics and trait bounds users of the library would have to know what the the type is of the concrete owner of the pixel data.
In other words users can simply write this Red<u8> to say: 'A red channel of a image where the sub pixels are u8 values'. Otherwise they would have to write this Red<Bitmap<RGBA<u8>>> which is needlessly verbose IMO.

The downside is that this comes with a performance penalty and I was worried that the performance of such a solution would be too much especially if I want to iterate over the pixel data.
It is dynamically dispatching on every pixel call which isn't great.

So my questions are:

  • Given the example I have given is this a suitable solution or is it possible to do this with just generic trait bounds?
  • What would be the performance implication of such a solution?

As a final thought I thought perhaps that for iterators I could delegate creating an iterator of the sub pixel data to the struct that owns the pixel data, and then pass it back to the caller.

Thank you.

That's really two questions :slight_smile:. It's hard to say if it's suitable without knowing the full use case and without trying it to see if it's fast enough. If you avoid the dynamic dispatch of dyn Trait by having monomorphized generic traits, you'll probably get faster execution at the cost of slower compilation. What's the right tradeoff depends on the situation.

As for the second question, yes it's possible without dyn Trait. I tried to stick to your original design, and this is what I ended up with. The most significant changes are probably the addition of a red_value associated method on RedChannel and the Sized requirements. It removed the dependence on RGBA<T> from the impl Image for Red<Img>.

Incidentally, have you considered the image crate? I don't know that it matches your use case exactly, but you may be able to piggy back on their traits and data structures to create your view-of-component structs.

Thank you very much.
Looking at your solution I definitely agree that RedChannel should have an associated type rather than a generic parameter.

However I think for now I will stick with my initial version since the generic parameter of Red is the sub-pixel type and not the parent image.
I think the reason I was unable to implement it using generics was that I was trying to create Red<u8> and not Red<Bitmap<RGBA<u8>>> as i explained above.

Yes I did although It isn't really suitable for my needs. I also disagree with some of the design decisions that the author made when it come to its public API, and choice of dependencies.

1 Like

As far as I know, there’s only two things that dyn Trait can do that generics can’t:

  • Store different object types in the same container (but enum can do a similar job)
  • Provide a type name for an anonymous type, like a closure or a future (the type_alias_impl_trait experimental feature provides this for generics)

On the other hand, the design restrictions you have to meet for dyn to be available for your trait cut off some useful features.