Once again fighting with polymorphism


#1

So, I need to do something that is pretty much the following:

https://is.gd/kwAEiY

which would work… except that in my actual code Stuff actually is

pub trait Stuff: Serialize + Deserialize + Hash {}

… which means it has methods that depend on Self and with type parameters (I’m using serde for de serialize/deserialize). So… no way to use trait objects…

Does any one have any idea how I can work around it?


#2

It depends on what exactly your need is here. For example, could you provide examples of methods that are not compatible with trait objects that you want to call on your trait objects? And we can go from there.


#3

How much flexibility do you have with respect to the current design? Could you, for example, create a FooExt and move (by virtue of requiring the serde and Hash impls there) all the object unsafe functions there? The “Ext” approach is what std used to do, I believe, to allow object unsafe functions on Iterator while allowing trait objects to be formed from Iterator. I think at some point (shortly before 1.0?) object safety was changed such that it could be achieved by putting a “where Self: Sized” constraint on the object unsafe methods, and compiler would “ignore” them when determining object safety of the rest of the trait - that’s how Iterator is defined now. Of course this requires you have control of the trait and can reshape it like that, which isn’t the case here.

Also, supposing you could form trait objects - what would you do with them? Your playground example is a bit too barebones to figure out what you’re really after.


#4

Here’s more or less how it should work (I also noticed I made some mistakes on the original playground):

https://is.gd/PWU90O

I’m now noticing some other errors that my implementation might have, I guess I hadn’t hit them before because of the other errors.

About flexibility, well, I have all the flexibility in the world, theoretically… I’m reimplementing a Java library from work and ironing out some problems it had. But ideally I’d like to keep the APIs as close as possible.

Could you give me an example of how this might work?

Thanks!


#5

Nothing fancy. Your Foo trait would not derive Serialize, Deserialize, Hash (or any other object unsafe trait). Instead, you’d create a new trait, FooExt:

trait FooExt: Foo, Serialize, Deserialize, Hash {}

The places where you need the serde and/or hash functionality, you’d use generics. In the places where you’d like to store them in trait objects, you’d use just Foo.


#6

Jesus, that might be an amazing way of solving it…

Tomorrow I’ll definitely try it out.