#Implement Generic trait for every value in a primitive variant

8 messages · Page 1 of 1 (latest)

empty perch
#

I have this enum:

pub enum Op {
    Add,
    Sub,
    Mul,
    Div,
}
pub enum Primitive {
    Number(f64),
    String(String),
    Iterable(IterableKind),
    Graph(Graph),
    GraphEdge(GraphEdge),
    GraphNode(GraphNode),
    Tuple(Tuple),
    Boolean(bool),
    Undefined,
}

and i want to do things like "binary operators" between any of 2 primitives (for example i want to be able to define an operator for String + number etc)
I tried to do this:

trait ApplyOp{
    type Target;
    fn apply_op(&self, op: Op, to: &Self::Target) -> Result<Self::Target, OperatorError>;
}

trait ApplyToPrimitiveOp: ApplyOp<Target = Primitive> {

}

impl ApplyToPrimitiveOp for i32 {
    pub fn apply_op(&self, op: Op, to: Primitive) -> Result<Primitive, OperatorError>{
        todo!()
    }
}
//i'd have to do the same for String, IterableKind, Graph, GraphEdge etc...

but i get the error:

`fn apply_op` is not a member of trait `ApplyToPrimitiveOp`rust-analyzerE0407
method `apply_op` is not a member of trait `ApplyToPrimitiveOp`
not a member of trait `ApplyToPrimitiveOp`

My end goal is to be able to do:

Exp::BinaryOperation(op, lhs, rhs) => {
    //TODO implement operator overloading for every primitive
    let lhs = lhs.as_primitive(context)?;
    let rhs = rhs.as_primitive(context)?;
    lhs.apply_op(op, rhs)
}

How could i do it?

#

Is this because of the orphan rule? do i need to make wrappers that wrap the primitive types (f64, String, bool) ?

long aspen
#

It's because apply_op is defined on the ApplyOp trait but your impl block says you're implementing ApplyToPrimitiveOp at the point where you're trying to define that

You need to implement ApplyToPrimitiveOp separately from ApplyOp

hot badge
#

so impl ApplyOp instead of impl ApplyToPrimitiveOp

#

and impl ApplyToPrimitiveOp separately

empty perch
long aspen
#

?play

#[derive(Debug)]pub struct Graph;
#[derive(Debug)]pub struct IterableKind;
#[derive(Debug)]pub struct GraphEdge;
#[derive(Debug)]pub struct GraphNode;
#[derive(Debug)]pub struct Tuple;
#[derive(Debug)]pub struct OperatorError;

#[derive(Debug)]
pub enum Op {
    Add,
    Sub,
    Mul,
    Div,
}

#[derive(Debug)]
pub enum Primitive {
    Number(f64),
    String(String),
    Iterable(IterableKind),
    Graph(Graph),
    GraphEdge(GraphEdge),
    GraphNode(GraphNode),
    Tuple(Tuple),
    Boolean(bool),
    Undefined,
}

// <---------------------------------------------------------------------------------------

trait ApplyOp {
    type Target;
    fn apply_op(&self, op: Op, to: &Self::Target) -> Result<Self::Target, OperatorError>;
}

trait ApplyToPrimitiveOp: ApplyOp<Target = Primitive> {
}

impl ApplyOp for i32 {
    type Target = Primitive;
    fn apply_op(&self, op: Op, to: &Primitive) -> Result<Primitive, OperatorError>{
        println!("Applying operation {op:?} on {self:?} with rhs {to:?}");
        Ok(Primitive::Undefined)
    }
}

impl ApplyToPrimitiveOp for i32 {}

// ---------------------------------------------------------------------------------------->

fn test_doing_something_with_apply_to_primitive_op(lhs: impl ApplyToPrimitiveOp, op: Op, rhs: Primitive) {
    lhs.apply_op(op, &rhs).unwrap();
}

fn main() {
    test_doing_something_with_apply_to_primitive_op(42, Op::Add, Primitive::Number(11.5));
}
red smeltBOT
#
Applying operation Add on 42 with rhs Number(11.5)```