How to set a constant generic field in a Trait?

Let me clarify what I mean:

I have a struct called Agent, which would be used like so:

let agent : Agent<PolicyRandom>= Agent::new(); 

And the policy PolicyRandom is a type having to implement TraitPolicy.

trait TraitPolicy<T: TraitModel> {
    const POLICY_NAME: &'static str;
    const MODEL: T;  //  IMPORTANT
    fn new() -> Self{}
    fn train(&self);
}

The specific Policy:

struct PolicyRandom {
    num: usize,
}

impl TraitPolicy<MyModel2> for PolicyRandom {
    const POLICY_NAME: &'static str = "Earth";
    const MODEL: MyModel2 = MyModel2 {};
    ...
}

Now here comes the problem when defining struct for Agent:

struct Agent<T: TraitPolicy> {//ERROR: missing generics for trait `TraitPolicy` expected 1 generic argument
    policy: T,
}

impl<T> Agent<T> {
    pub fn new() -> Self {
        Self { policy: T::new() }
    }
}

The error tells me that I need to add signature for the model type I use. But this is not what I want---I don't want to add another ModelType when initialing an agent object with type other than PolicyType.

Someone may wonder: "Why using generic type with TraitPolicy?"----Because I require every specific policyType has a field called model implementing TraitModel, while each specific policyType ONLY need ONE specifc model.

Therefore, if I change TraitPolicy into this without generic:

trait TraitPolicy {
    const POLICY_NAME: &'static str;
    const MODEL: impl TraitModel;// syntax ERROR!
...
}

It is not compilable. I don't know How to solve it.
Also, actually, I don't care whether the field MODEL is constant or not. But It seems that I can't make it unconstant in Trait, syntaxlly.

It sounds like you should remove the generic parameter.

This doesn't make sense because generic parameters such as T are always types, but the right-hand-side of the colon here must be a trait. I can't read. Please disregard.

You need an associated type instead of a parameter:

trait TraitPolicy {
    type Model: TraitModel;
    const POLICY_NAME: &'static str;
    const MODEL: Self::Model;
    fn new() -> Self;
    fn train(&self);
}

Associated types are what you use whenever each implementor of the trait should specify one such type, which sounds like exactly your situation.

3 Likes

Thanks. That is what I ask. But now I have a side question, if the MODEL need to initialized by some parameters input only feasible when a specific policy is initialized, is that possbile?

trait TraitModel {
    fn new(shape_size:usize) -> Self;
    ...
}
impl TraitPolicy for PolicyRandom {
    const POLICY_NAME: &'static str = "Earth";
    // MODEL
    type Model = MyModel2;
    const MODEL: MyModel2 = MyModel2::new(shape_size); // how to get the param shape_size??????
...
}

In that case, MODEL isn't a constant because shape_size isn't a constant. So whatever purpose it is serving, you will need to satisfy in some way involving functions, not constants. I don't know exactly what to suggest, because it's not clear what the function version of MODEL would be doing that TraitModel::new isn't already.

1 Like

Thanks for your reply. Actually, whenever a new policy struct is designed, I hope it has a field called model which implement TraitModel.It is actually not a business with constant or not. But grammatically, it seems that the field model has to be declared as a constant in TraitPolicy. Or is there some other workaound?

Currently there is no way for a trait to require a field be present, but you could instead do

trait TraitPolicy {
    type Model: TraitModel;
    fn model(&self) -> &Self::Model;
    fn model_mut(&mut self) -> &mut Self::Model; // if you want mutable access

    // (.. everything else ..)
}

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.