Reputation: 956
I have a fairly complex trait set up and I'm having trouble lining the pieces up. Right now it looks roughly like this:
/// Trait for models which can be gradient-optimized.
pub trait Optimizable {
type Data;
type Target;
// The contract //
}
/// Trait for optimization algorithms.
pub trait OptimAlgorithm<M : Optimizable> {
// The contract //
}
Now I want to be able to allow a struct implementing OptimAlgorithm
to be a field in a struct implementing Optimizable
. This would look something like this:
/// Model struct
pub struct Model<A: OptimAlgorithm<Self>> {
alg: A,
}
impl Optimizable for Model<A> {
...
}
This doesn't work as the Self
reference on the struct is nonsense. I tried using associated types for OptimAlgorithm
but I need the algorithms to be generic over the models so this doesn't work. Is there a magic syntax I'm missing or does this need an overhaul?
Edit --
Here's a minimal example which shows error E0275 as described in Steven's answer. It's a little closer to my source code but less messy.
Upvotes: 2
Views: 502
Reputation: 25844
I think it's a bug. Or at least surprising behaviour.
If you take off the where
bound on the Model
struct (and just leave it on the impl
), your edited code compiles.
I'll try to reduce a bit more and file a bug.
pub trait Optimizable {
type Data;
type Target;
// The contract //
}
/// Trait for optimization algorithms.
pub trait OptimAlgorithm<M: Optimizable> {
// The contract //
}
pub struct Algorithm;
impl Default for Algorithm {
fn default() -> Algorithm { Algorithm }
}
impl<M: Optimizable> OptimAlgorithm<M> for Algorithm {
}
pub struct Model<'a, A> { // no bounds here
layer_sizes: &'a [usize],
alg: A,
}
impl<'a, A> Model<'a, A>
where A: OptimAlgorithm<Model<'a, A>>
{
pub fn new(layers: &[usize]) -> Model<Algorithm> {
Model {
layer_sizes: layers,
alg: Algorithm::default(),
}
}
}
impl<'a, A> Optimizable for Model<'a, A>
where A: OptimAlgorithm<Model<'a, A>>
{
type Data = ();
type Target = ();
}
pub fn main() {
}
Upvotes: 2
Reputation: 5770
Just use Model<A>
instead of Self
. Self
is only really useful in traits where one needs to be able to refer to the concrete type implementing the trait. Here, the concrete type is always Model<A>
.
pub trait Optimizable {
type Data;
type Target;
// The contract //
}
/// Trait for optimization algorithms.
pub trait OptimAlgorithm<M: Optimizable> {
// The contract //
}
pub struct Model<A> where A: OptimAlgorithm<Model<A>> {
alg: A,
}
impl<A> Optimizable for Model<A>
where A: OptimAlgorithm<Model<A>>
{
type Data = ();
type Target = ();
}
In response to your updated code, the lifetime appears to be giving rust trouble. It appears you can make this work by using a higher-ranked lifetime but I don't know why.
pub trait Optimizable {
type Data;
type Target;
// The contract //
}
/// Trait for optimization algorithms.
pub trait OptimAlgorithm<M: Optimizable> {
// The contract //
}
pub struct Algorithm;
impl Default for Algorithm {
fn default() -> Algorithm { Algorithm }
}
impl<M: Optimizable> OptimAlgorithm<M> for Algorithm {
}
pub struct Model<'a, A> where for<'b> A: OptimAlgorithm<Model<'b, A>> {
layer_sizes: &'a [usize],
alg: A,
}
impl<'a, A> Model<'a, A>
where A: for<'b> OptimAlgorithm<Model<'b, A>>
{
pub fn new(layers: &'a [usize]) -> Model<Algorithm> {
Model {
layer_sizes: layers,
alg: Algorithm::default(),
}
}
}
impl<'a, A> Optimizable for Model<'a, A>
where A: for<'b> OptimAlgorithm<Model<'b, A>>
{
type Data = ();
type Target = ();
}
pub fn main() {
let layers = &[1usize,2,3];
let a = Model::<Algorithm>::new(layers as &[usize]);
}
Upvotes: 4