A supertrait problem

Hello. I have a problem. Here is a struct Position implemented Component, and I want to implement another trait called ComponentVec for the vec of components(such as Position). So I wrote this:

pub trait Component {}
pub trait ComponentVec {}

struct Position {
    x: f32,
    y: f32,
    z: f32,
}
impl Component for Position {}
impl ComponentVec for Vec<Option<Position>> {}

There is the problem. It should be that ComponentVec had to be a vec of components rather than a vec of other types. But what I wrote cannnot assure that. In fact, I can even remove the line "impl Component for Position {}", and it wont make any warn or error.

Since some reasons, ComponentVec have to be a trait but not a struct and with no generic arguments.

I tried supertrait and where clause, but they cannot solve my problem:

// 1.
pub trait ComponentVec: Vec<Option<......>> // wrong

// 2.
pub trait ComponentVec
where Self : ......  

Sorry for my bad English. Can anyone help me with the problem?

Um. What problem? So far i see that everything behaves as it should and there are no any problems at all.

Well, you are forcibly and without explanation rejecting the one solution that is specifically designed to combat problem that you, purportedly, have… but why?

But… why? That's sounds like such an arbitrary requirement. What do you really want to achieve? You want to iterate over components? There's Iterator for that. You want to ensure that someone wouldn't implement ComponentVec for something otehr than fixed set of types? There are sealed traits for that.

What are you really after? You are putting some arbitrary restrictions on your design and, worse, of style that Rust is, very much, designed to prevent… and then complain that it doesn't work.

That doesn't mean there's no problems… it's just I don't see any just yet.

**Why would you even that ComponentVec is only implemented on Vec and not on something like Triangle which is (Position, Position, Position) ? What would such implementation make possible that you are attempting to prevent?

I thought my question is clear enough. It is how to make sure that ComponentVec works as a vec only for components.
Why I want that restriction? Because the trait objects are named ComponentVec, not WhateverVec.

You said sealed traits can help me. But I dont see that. Maybe there is a solution. So can you please help me out of the documents of sealed traits as I cannot read English much, and show me how you will use sealed traits to make this restriction? That is what this post expects.

And you have question for my design. If you have written about ecs. I will be happy to learn from you about how to design a more elegant structure that will not result in these problem that seem to be unnecessary or meaningless as you find.

Rename the trait, then. Problem solved. If that's the only reason you want it.

You were. As in: you described the situation precisely like in a joke:

  • Doctor, it hurts when I do this.
  • Then don't do that!

This either means you are trying something strange or you are not describing the issue clearly enough.

Not every restriction is meant to be expressible in Rust. And especially not the restriction with justification like “I named it X thus it have to do X”.

It's not about the “elegant structure” but about “arbutrary restructions”.

You said that you want ComponentVec to be a vector of components. Okay.

But why restrict it to Vec? Why not ArrayVec? Or maybe just array? Or, heck, a tuple (like I already asked)?

Who even decides what vector is and isn't and why?

Sealed traits allow you to operate with “closed set” of types. Something like this:

pub trait Component {}
pub trait ComponentVec : sealed::MustBeAVector {}

struct Position {
    x: f32,
    y: f32,
    z: f32,
}
impl Component for Position {}
impl ComponentVec for Vec<Option<Position>> {} // Compiles.

impl ComponentVec for [Option<Position>] {} // Doesn't compile.

mod sealed {
    pub trait MustBeAVector {}
    impl<T> MustBeAVector for Vec<T> {}
}

1 Like

If you do it like this:

impl<T> ComponentVec for Vec<Option<T>> where T: Component

Then Rust will stop you from assuming anything about the unknown type T, other than it implements component. You won't be allowed to use any struct fields, and you won't be allowed to use any methods that aren't in trait Component.

5 Likes

The sealed trait I want is "WhoseElementsMustBeComponents", not "MustBeAVector". In both the post and the reply to you, I haven't said to be a vector is a problem or I care its collective form. It definitely can be other collections or a tuple.

What I care is "only contains Component". And how can this "only contains Component" restriction be achieved by changing the code about ComponentVec. It's not me but you who insist on the topic of "Having to be a vector".

You see that? You always put your true answer or the the only helpful content at the last of your reply, after all your witty refutation, precise citations, humourous insights and quips about a new question that I didn't mention.

I am not commenting the way you talk or help, you are helping me actually. But to be honest, If you reply a question only by a answer, or at least put your answer at the first place, it will save a lot of time for both of us.

One possible formalization of this as a bound you can express in Rust is

T: Deref<Target = [U]>`,
U: Component,

However, this does not accept any container that doesn't store the elements contiguously in a slice.

For the question "what do you want this trait to do?"
One way to answer is through a function using an instance of the trait.

What do you want to do with instance inside a function that uses it?

fn example_use<T>(instance: T)
where T: ComponentVec
{
    // TODO use `instance`
}

Examples of answers:

  • for loop to iterate over the components
  • get the number of components
  • ...etc

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.