What's the name of this design pattern?

In the library I am working on I have extensively applied the following pattern. I would like to know the name of such pattern.

The library has a trait MyBounds with a method hello:

trait MyBounds {
    type Inner;

    fn hello(&mut self);
}

In the library, the trait is implemented by Base<ExtensionOne> and Base<ExtensionTwo>:

struct Base<E> {
    extension: E,
    // common fields
    common: u32,
}
struct ExtensionOne;

impl MyBounds for Base<ExtensionOne> {
    type Inner = ExtensionOne;

    fn hello(&mut self) {
        println!("hello + ExtensionOne");
        let common: u32 = self.common;
        // Use the specific fields contained in ExtensionOne
        let extension_one: &mut ExtensionOne = &mut self.extension;
    }
}
struct ExtensionTwo;

impl MyBounds for Base<ExtensionTwo> {
    type Inner = ExtensionTwo;

    fn hello(&mut self) {
        println!("hello + ExtensionTwo");
        let common: u32 = self.common;
        // Use the specific fields contained in ExtensionTwo
        let extension_two: &mut ExtensionTwo = &mut self.extension;
    }
}

By using this pattern, the implementations of MyBounds can access the Inner field and implement type-specific behavior, but still share some "common" fields of Base.

Finally, the library has the two following equivalent functions:

fn takes_mystruct<E>(mut s: Base<E>)
where
    Base<E>: MyBounds,
{
    s.hello();
}

fn takes_mybounds<B>(mut bounds: B)
where
    B: MyBounds,
{
    bounds.hello();
}
Which the user can, for example, invoke as follows.
fn main() {
    takes_mybounds(Base {
        extension: ExtensionOne,
        common: 0,
    });
    takes_mybounds(Base {
        extension: ExtensionTwo,
        common: 0,
    });

    takes_base(Base {
        extension: ExtensionOne,
        common: 0,
    });
    takes_base(Base {
        extension: ExtensionTwo,
        common: 0,
    });
}

I don’t know if it has a special name in the Rust world, but this looks like you’ve manually implemented C++-style implementation inheritance (though that would usually put the extension field last for technical reasons).

1 Like

AFAIK this pattern doesn't officially have a name.

I sure there are exceptions, but in general I've found that when patterns become a Big Thing™️ in a programming language community, it's an indication that the language itself has failed to provide tools to properly abstract over all the boilerplate that makes up the pattern.
If a pattern is used so much in a PL community that it needs a name, then a better solution is to just be able to abstract over it, and perhaps provide additional compile time checks in the process.

2 Likes

I'm not sure what you want to use Inner for, since it's unused. In fact you can even remove it and it will still compile fine.

1 Like

I was trying to simplify the library code I mentioned at the beginning of the post, where the associated type is required (the reasons are quite complicated).

But yeah, you are right: my post could be further simplified.
Still, even with the simplification, I can't tell the design pattern in use.

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.