Extending On An SO Answered Question About Strategy Pattern Implementation - rust

As answered by the ever so helpful and ubiquitous Shepmaster, could someone help me with a syntax hurdle I'm encountering?
In the previous answer, Strategy::execute() and Context::do_things() returns ().
How does one implement if a generic type is returned? Or am I missing some fundamental perspective in Rust?
I tried the following code but am currently stuck at:
struct Context<S> {
strategy: S,
}
impl<S> Context<S>
where
S: Strategy,
{
fn do_things(&self) -> T {
println!("Common preamble");
self.strategy.execute()
}
}
trait Strategy<T> {
fn execute(&self) -> T;
}
struct ConcreteStrategyA;
impl Strategy<AStruct> for ConcreteStrategyA {
fn execute(&self) -> AStruct {
println!("ConcreteStrategyA");
AStruct::default()
}
}
struct AStruct {
id: u32,
}
impl Default for AStruct {
...
}
struct ConcreteStrategyB;
impl Strategy<BStruct> for ConcreteStrategyB {
fn execute(&self) -> BStruct {
println!("ConcreteStrategyB");
BStruct::default()
}
}
struct BStruct {
id: u32,
}
impl Default for BStruct {
...
}
I have no idea where to put T for Context::do_things() -> T.
I looked around but some other samples return () as well.
Online tinkering
Thanks for reading.

Depending on what you're trying to do, it might be better to use an associated type instead of a generic. When choosing between associated types and generic parameters, you should use a generic if the caller can choose the type to use. You should use an associated type if the implementation determines the type.
Although there are exceptions (e.g. Into::into), most of the time if a type appears only in the return of a method, then this is a good indication that it should probably be an associated type. OTOH if a type is used for a parameter, then there is a fair chance that it should be a generic.
In your case, using an associated type would look like this:
struct Context<S> {
strategy: S,
}
impl<S> Context<S>
where
S: Strategy,
{
fn do_things(&self) -> S::Output {
println!("Common preamble");
self.strategy.execute()
}
}
trait Strategy {
type Output;
fn execute(&self) -> Self::Output;
}
struct ConcreteStrategyA;
impl Strategy for ConcreteStrategyA {
type Output = AStruct;
fn execute(&self) -> AStruct {
println!("ConcreteStrategyA");
AStruct::default()
}
}
#[derive (Default)]
struct AStruct {
id: u32,
}
struct ConcreteStrategyB;
impl Strategy for ConcreteStrategyB {
type Output = BStruct;
fn execute(&self) -> BStruct {
println!("ConcreteStrategyB");
BStruct::default()
}
}
#[derive (Default)]
struct BStruct {
id: u32,
}
Playground

I think using Strategy<T> more often is the key:
impl<S, T> Context<S, T>
where
S: Strategy<T>,
{
fn do_things(&self) -> T {
println!("Common preamble");
self.strategy.execute()
}
}
See here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a3a14895e22ca57f5f96c855b7046257

Related

Propagating higher-kinded-lifetimes? implementation of `Predicate` not general enough

I'm trying to write a Rust library that lets users define and compose predicates for certain kinds of data. This is all easy when the predicates act on owned data, but it's turning out to be harder when they act on borrowed data. I think it's easier to understand my problem by reading an annotated code example (I'm sorry I couldn't make it shorter, but I think everything in it is required to understand my situation).
// First, some of the types that I'm interested in writing predicates for. MyValue and
// MyParsedBorrowedValue
struct MyValue {
a: String
}
struct MyParsedBorrowedValue<'a> {
_name: &'a str,
_last_name: &'a str
}
fn parse_value(value: &MyValue) -> MyParsedBorrowedValue<'_> {
// (imagine some parsing that borrows from MyValue)
MyParsedBorrowedValue {
_name: &value.a,
_last_name: &value.a
}
}
// Now, imagine I have this trait
trait Predicate<T> {
fn passes(&self, t: &T) -> bool;
}
// I can write a generic combinator like:
struct Not<T, P: Predicate<T>> {
p: P,
_p: std::marker::PhantomData<T>
}
impl<T, P: Predicate<T>> Not<T, P> {
fn new(p: P) -> Not<T, P> { Not { p, _p: std::marker::PhantomData }}
}
impl<T, P: Predicate<T>> Predicate<T> for Not<T, P> {
fn passes(&self, t: &T) -> bool {
!self.p.passes(t)
}
}
// I can write predicates on MyValue. For example:
struct IsMyValueGood {}
impl Predicate<MyValue> for IsMyValueGood {
fn passes(&self, _t: &MyValue) -> bool {
// some processing
true
}
}
// I can also write predicates on MyBorrowedParsedValue
struct IsMyParsedBorrowedValueGood {}
impl<'a> Predicate<MyParsedBorrowedValue<'a>> for IsMyParsedBorrowedValueGood {
fn passes(&self, _t: &MyParsedBorrowedValue<'a>) -> bool {
// some processing ...
false
}
}
// Finally, and this is the most important bit: I want a function that would take a
// Predicate on a "MyParsedBorrowedValue" and transform it into a predicate for a
// MyValue. Something like:
fn map_predicates(p: impl for<'a> Predicate<MyParsedBorrowedValue<'a>>)
-> impl Predicate<MyValue> {
// I believe this is a good use of higher-kinded lifetimes, though I'm not very
// familiar with them.
struct PredicateMapper<P: for<'a> Predicate<MyParsedBorrowedValue<'a>>> {
p: P
}
impl<P: for<'a> Predicate<MyParsedBorrowedValue<'a>>> Predicate<MyValue> for PredicateMapper<P> {
fn passes(&self, value: &MyValue) -> bool {
self.p.passes(&parse_value(value))
}
}
PredicateMapper { p }
}
// This is all good but sadly the following does not compile:
fn compose_predicates() {
// This compiles:
let complex_predicate_1 = map_predicates(IsMyParsedBorrowedValueGood{});
// This doesn't compile!
// Error: implementation of `Predicate` is not general enough
let complex_predicate_2 = map_predicates(Not::new(
IsMyParsedBorrowedValueGood {}
));
}
Link to compiler explorer https://godbolt.org/z/oonfcMdK3
I understand that the Not combinator is not propagating the for <'a> outside, which is what map_predicate needs to do its job. However, I don't know how I would get Not to do that, given that its definition doesn't involve any lifetimes. I guess I could make a custom NotMyParsedBorrowedValue that handles the lifetimes in the correct way, but I would prefer having a single Not combinator that works for all kinds of predicates. Is this possible?

Return object implementing multiple traits - decorator pattern

I am currently implementing decorator pattern in Rust.
In Scala we could implement method chaining via traits like:
new Scanner
with Whitespaces
with Keywords
I want to do the same in Rust. So, different traits for scanner:
pub struct Lexer();
pub trait Scan {
fn scan(&self, start: &String) -> DomainTags;
}
pub struct Keywords<T> {
decorated: T
}
impl<T: Scan> Scan for Keywords<T> {
fn scan(&self, start: &String) -> DomainTags {
...
}
}
pub struct Whitespaces<T> {
decorated: T
}
impl<T: Scan> Scan for Whitespaces<T> {
fn scan(&self, start: &String) -> DomainTags {
...
}
}
But since I want to build my lexers with method like:
pub fn build() -> ??? {
let lex = Lexer();
let lex = Keyword {
decorated: Whitespaces {
decorated: lex
}
};
lex
}
I don't know if it is possible to statically deduce the return type to something like decltype(lex). What is the common approach, towards implementing the method? What could be improved?
To clarify: I want to return decltype(lex), because I may also have multiple traits for single Lexer, like:
pub trait Load {
fn load<T : Load>(&self, keywords: &String);
}
impl Load for Lexer {
fn load<Lexer>(&self, keyword : &String) {
...
}
}
And I hope to return a decorated object with implementation of Load trait as well. Both method load and scan should be available.
A function can only return a single type of value, so the type returned by your function can't depend on runtime conditions. However that type may be a boxed trait, in which case the type of the value stored in the box may change provided it implements the appropriate trait (or traits).
From the example code you've provided, I think that Lexer should be a trait like trait Lexer: Scan + Load {} (or maybe the Scan and Load traits don't need to exist at all and the scan and load methods can be defined directly in Lexer). Then your build function should just return a boxed Lexer:
pub trait Lexer {
fn scan (&self, start: &String) -> DomainTags;
fn load (&self, keyword : &String);
}
pub struct Keywords<T> {
decorated: T
}
impl<T: Lexer> Lexer for Keywords<T> {
…
}
pub struct Whitespaces<T> {
decorated: T
}
impl<T: Lexer> Lexer for Whitespaces<T> {
…
}
pub fn build (cond: bool) -> Box<dyn Lexer> {
if cond {
Box::new (Whitespaces { … })
} else {
Box::new (Keywords { … })
}
}

How do I 'force' structs to implement the same traits?

I have the following:
pub struct OpBStruct {
title: String,
output_vale: i32,
}
impl OpBStruct {
pub fn new_OpB(in_title: String, in_output_vale: i32) -> OpBStruct {
OpBStruct {
title: in_title,
output_vale: in_output_vale,
}
}
}
pub struct OpCStruct {
title: String,
another_value: String,
output_vale: i32,
}
impl OpCStruct {
pub fn new_OpC(in_title: String, in_another_value: String, in_output_vale: i32) -> OpCStruct {
OpCStruct {
title: in_title,
another_value: in_another_value,
output_vale: in_output_vale,
}
}
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
pub enum Op {
OpB(OpBStruct),
OpC(OpCStruct),
}
pub struct A {
name: String,
operator: Op,
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
The exact structure of OpBStruct and OpCStruct are arbitrary and could be anything.
How do I make sure OpBStruct and OpCStruct implement a certain trait?
trait OpTrait {
pub fn get_op_output(&self) -> i32;
}
I thought about making a sort of constructor function that checked for an OpTrait trait requirement and it would be the only way one could create an Op instance, but each operator requires different initialization parameters and there's no way to specify a variable number of inputs for a function in Rust.
Something like this doesn't work because there's no way to input the initialization parameters:
pub fn new_op<T: OpTrait>(operator: T) {
// --snip--
}
I thought about somehow using the new_A method implemented on A to check if the in_operator has implemented the trait, but I'm not sure how to do that either.
What is the correct pattern for this? If there is none, I can just implement the trait for each Op with no sort of interface around it.
I would also recommend writing a test, however you can write a function which is generic over a type but takes no arguments:
struct X {}
trait Y {
fn yo();
}
fn is_y<T: Y>(){}
Then you can add the following line to do the check
is_y::<X>();
which will compile only if X implements Y.
Using a unit test would be a fairly straightforward way to enforce that you want a given trait on a struct. You can do it via implicit test code, but a small utility function to do so can express the intent a little more clearly.
If you have indicated trait inputs on functions in the rest of the code, it might come out fairly naturally without the unit test. The test has the advantage of letting you have an opportunity to explicitly check some invariant of the trait implementation too.
struct A {
val: u8,
}
struct B {
val: u32,
}
trait ExpandToU64 {
fn to_u64(&self) -> u64;
}
impl ExpandToU64 for A {
fn to_u64(&self) -> u64
{
self.val as u64
}
}
fn trait_tester<E>(a: E)
where E: ExpandToU64
{
// the utility function doesn't have to even use the trait...
// but you probably want to exercise the logic a bit
//let v = a.to_u64();
let v = 24u64;
println!("{:?}", v);
}
#[test]
fn test_needs_trait_ExpandToU64() {
let a = A { val:1 };
trait_tester(a);
let b = B { val:2 };
trait_tester(b);
// This fails with a compile error
// "the trait `ExpandToU64` is not implemented for `B`"
}

Rust extend struct fields? [duplicate]

Using rust 1.2.0
Problem
I'm still in the process of learning Rust (coming from a Javascript background) and am trying to figure out if it is possible for one struct StructB to extend an existing struct StructA such that StructB has all the fields defined on StructA.
In Javascript (ES6 syntax) I could essentially do something like this...
class Person {
constructor (gender, age) {
this.gender = gender;
this.age = age;
}
}
class Child extends Person {
constructor (name, gender, age) {
super(gender, age);
this.name = name;
}
}
Constraints
StructA is from an external cargo package that I have no control over.
Current Progress
I found this blog post on single-inheritance which sounds like exactly what I need.
But trying to implement it resulted in this error message error: virtual structs have been removed from the language. Some searching later and I found out that it had been implemented and then removed per RFC-341 rather quickly.
Also found this thread about using traits, but since StructA is from an external cargo package I don't think it is possible for me to turn it into a trait.
So what would be the correct way to accomplish this in Rust?
There is nothing that exactly matches that. There are two concepts that come to mind.
Structural composition
struct Person {
age: u8,
}
struct Child {
person: Person,
has_toy: bool,
}
impl Person {
fn new(age: u8) -> Self {
Person { age: age }
}
fn age(&self) -> u8 {
self.age
}
}
impl Child {
fn new(age: u8, has_toy: bool) -> Self {
Child { person: Person::new(age), has_toy: has_toy }
}
fn age(&self) -> u8 {
self.person.age()
}
}
fn main() {
let p = Person::new(42);
let c = Child::new(7, true);
println!("I am {}", p.age());
println!("My child is {}", c.age());
}
You can simply embed one struct into another. The memory layout is nice and compact, but you have to manually delegate all the methods from Person to Child or lend out a &Person.
Traits
trait SayHi {
fn say_hi(&self);
}
struct Person {
age: u8,
}
struct Child {
age: u8,
has_toy: bool,
}
impl SayHi for Person {
fn say_hi(&self) {
println!("Greetings. I am {}", self.age)
}
}
impl SayHi for Child {
fn say_hi(&self) {
if self.has_toy {
println!("I'm only {}, but I have a toy!", self.age)
} else {
println!("I'm only {}, and I don't even have a toy!", self.age)
}
}
}
fn greet<T>(thing: T)
where T: SayHi
{
thing.say_hi()
}
fn main() {
let p = Person { age: 42 };
let c = Child { age: 7, has_toy: true };
greet(p);
greet(c);
}
You can combine these two concepts, of course.
As DK. mentions, you could choose to implement Deref or DerefMut. However, I do not agree that these traits should be used in this manner. My argument is akin to the argument that using classical object-oriented inheritance simply for code reuse is the wrong thing. "Favor composition over inheritance" => "favor composition over Deref". However, I do hold out hope for a language feature that enables succinct delegation, reducing the annoyance of composition.
Rust does not have struct inheritance of any kind. If you want StructB to contain the same fields as StructA, then you need to use composition.
struct StructB {
a: StructA,
// other fields...
}
Also, to clarify, traits are only able to define methods and associated types; they cannot define fields.
If you want to be able to use a StructB as a StructA, you can get some of the way there by implementing the Deref and DerefMut traits, which will allow the compiler to implicitly cast pointers to StructBs to pointers to StructAs:
struct StructA;
impl StructA {
fn name(&self) -> &'static str {
"Anna"
}
}
struct StructB {
a: StructA,
// other fields...
}
impl std::ops::Deref for StructB {
type Target = StructA;
fn deref(&self) -> &Self::Target {
&self.a
}
}
fn main() {
let b = StructB { a: StructA };
println!("{}", b.name());
}
Another alternative is to use generics:
trait IAnimalData {}
struct Animal<D: IAnimalData> {
name: String,
age: i64,
child_data: D,
}
struct Dog {
favorite_toy: String,
}
impl IAnimalData for Dog {}
And then you can implement "child" methods like this, which will only apply to dogs:
impl Animal<Dog> {
pub fn bark(&self) -> String {
return "bark!".to_owned();
}
}
And if you want parent methods that apply to all animals, you can implement them like this:
// implements the 'breathe' method for all animals
impl<T: IAnimalData> Animal<T> {
fn breathe() {}
}
The good part is that you don't have to go through the pain of forwarding methods in Dog to methods in Animal; you can use them directly inside impl Animal<Dog>. Also, you can access any fields defined in Animal from any method of Animal<Dog>. The bad part is that your inheritance chain is always visible (that is, you will probably never use Dog in your code, but rather Animal<Dog>). Also, if the inheritance chain is long, you might get some very silly, long-winded types, like Animal<Dog<Chihuahua>>. I guess at that point a type alias would be advisable.
One thing that is good to mention for new corners in Rust is the way to design your structs/classes/traits. Try to keep your traits small and simple.
And take advantage of possible to use multiples traits for the same class:
trait Animal {
fn print_name(&self);
}
trait Attack {
fn can_kick(&self) -> bool {
false
}
}
trait Behavior {
fn can_fly(&self) -> bool {
true
}
}
impl Aminal for Bird {}
impl Behavior for Bird {}
impl Attack for Bird {}
Ok, the answer is very simple. Use macro.
macro_rules! Person {
(#[derive($($derive:meta),*)] $pub:vis struct $name:ident { $($fpub:vis $field:ident : $type:ty,)* }) => {
#[derive($($derive),*)]
$pub struct $name {
// required for all persones
age: i64,
$($fpub $field : $type,)*
}
impl $name {
$pub fn new(age:i64,$($field:$type,)*) -> Self{
Self{
age,
$($field,)*
}
}
}
}
}
And then use it like this:
Person! {
pub stuct Kid {
extra_field: String,
}
}

Mismatched types error when moving a method from a trait implementation to a trait definition

I have two structs, VM and Word. I need a new struct Control which behaves just like VM, but with one more field master. Because Rust has no inheritance, I try to extend the struct through composition. I move the functions of VM into a new trait Core, and implement Core for Control. The resulting code works.
struct Word<T> {
action: fn(target: &T)
}
struct VM {
word: Word<VM>
}
trait Core<T> {
fn word(&self) -> &Word<T>;
fn hello(&self) { println!("Hello"); }
fn execute(&self);
}
impl Core<VM> for VM {
fn word(&self) -> &Word<VM> { &self.word }
fn execute(&self) { (self.word().action)(self); }
}
struct Control {
word: Word<Control>,
master: i32,
}
impl Core<Control> for Control {
fn word(&self) -> &Word<Control> { &self.word }
fn execute(&self) { (self.word().action)(self); }
}
fn main() {
let vm = VM{
word: Word {action: Core::hello}
};
vm.execute();
let control = Control{
word: Word {action: Core::hello},
master: 0,
};
vm.execute();
}
The two implementation of execute are identical. So I move execute into trait Core.
trait Core<T> {
fn word(&self) -> &Word<T>;
fn hello(&self) { println!("Hello"); }
fn execute(&self) { (self.word().action)(self); }
}
impl Core<VM> for VM {
fn word(&self) -> &Word<VM> { &self.word }
}
impl Core<Control> for Control {
fn word(&self) -> &Word<Control> { &self.word }
}
Which compiles with the following error:
main.rs:14:44: 14:48 error: mismatched types:
expected `&T`,
found `&Self`
(expected type parameter,
found Self) [E0308]
main.rs:14 fn execute(&self) { (self.word().action)(self); }
How can I solve this problem?
if you move execute in Core, there is nothing in the trait definition that says that T is the same type as Self.
trait Core<T> {
fn word(&self) -> &Word<T>;
fn hello(&self) { println!("Hello"); }
fn execute(&self) {
(self.word() // this is a &Word<T>
.action) // this is a fn(T)
(self); // this type is Self. T is not necessarily = Self
}
}
When execute is in the impl Core<Control> for Control, the impl says that Self and T are both = Control, so execute works. But if T can be anything like in the definition of the trait, Rust can't let your code compile.
How to fix it depends on what you need to do.
If your trait is always meant to be implemented this way (impl Core<Something> for Something or impl Core<SomethingElse> for SomethingElse but NEVER as impl Core<Something> for SomethingElse), you can drop the parameter from the trait definition and have just:
trait Core: Sized {
fn word(&self) -> &Word<Self>; // now you can't parametrize what
// Word to return. It will be Self.
fn hello(&self) { println!("Hello"); }
fn execute(&self) { (self.word().action)(self); } // ...and this works
}

Resources