# Best way to express this algebra between Types

**URL:** <https://discourse.julialang.org/t/best-way-to-express-this-algebra-between-types/41891>\
**Category:** General Usage\
**Created:** [June 22, 2020, 8:37pm UTC](https://discourse.julialang.org/t/best-way-to-express-this-algebra-between-types/41891 "2020-06-22T20:37:41Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![francesco.alemanno](https://avatars.discourse-cdn.com/v4/letter/f/e8c25b/32.png) [@francesco.alemanno](https://discourse.julialang.org/u/francesco.alemanno)\
**Post date:** [June 22, 2020, 8:37pm UTC](https://discourse.julialang.org/t/best-way-to-express-this-algebra-between-types/41891/1 "2020-06-22T20:37:41Z")

</div>

```julia
struct Perturbator
    rng::AbstractRNG
end

function (a::Perturbator)()
    randn(a.rng)
end

const MultiLike = Union{Tuple,Array}

+′(a,b) = a + b
-′(a,b) = a - b
*′(a,b) = a * b
/′(a,b) = a / b

+′(a::T,b) where T <: MultiLike = a .+′ b
-′(a::T,b) where T <: MultiLike = a .-′ b
*′(a::T,b) where T <: MultiLike = a .*′ b
/′(a::T,b) where T <: MultiLike = a ./′ b

+′(a,b::T) where T <: MultiLike = a .+′ b
-′(a,b::T) where T <: MultiLike = a .-′ b
*′(a,b::T) where T <: MultiLike = a .*′ b
/′(a,b::T) where T <: MultiLike = a ./′ b

+′(a::T,b::R) where {T <: MultiLike,R <: MultiLike} = a .+′ b
-′(a::T,b::R) where {T <: MultiLike,R <: MultiLike} = a .-′ b
*′(a::T,b::R) where {T <: MultiLike,R <: MultiLike} = a .*′ b
/′(a::T,b::R) where {T <: MultiLike,R <: MultiLike} = a ./′ b

+′(a::R,b::T) where {T <: MultiLike,R <: MultiLike} = a .+′ b
-′(a::R,b::T) where {T <: MultiLike,R <: MultiLike} = a .-′ b
*′(a::R,b::T) where {T <: MultiLike,R <: MultiLike} = a .*′ b
/′(a::R,b::T) where {T <: MultiLike,R <: MultiLike} = a ./′ b

+′(a::T,b) where T<:Integer = round(T,a + b)
-′(a::T,b) where T<:Integer = round(T,a - b)
*′(a::T,b) where T<:Integer = round(T,a * b)
/′(a::T,b) where T<:Integer = round(T,a / b)

+′(a,b::T) where T<:Integer = round(T,a + b)
-′(a,b::T) where T<:Integer = round(T,a - b)
*′(a,b::T) where T<:Integer = round(T,a * b)
/′(a,b::T) where T<:Integer = round(T,a / b)

+′(a,b::Perturbator) = a +′ b()
-′(a,b::Perturbator) = a -′ b()
*′(a,b::Perturbator) = a *′ b()
/′(a,b::Perturbator) = a /′ b()

+′(a::Perturbator,b) = a() +′ b
-′(a::Perturbator,b) = a() -′ b
*′(a::Perturbator,b) = a() *′ b
/′(a::Perturbator,b) = a() /′ b

+′(a::T,b::Perturbator) where T <: MultiLike = a .+′ Ref(b)
-′(a::T,b::Perturbator) where T <: MultiLike = a .-′ Ref(b)
*′(a::T,b::Perturbator) where T <: MultiLike = a .*′ Ref(b)
/′(a::T,b::Perturbator) where T <: MultiLike = a ./′ Ref(b)

+′(a::Perturbator,b::T) where T <: MultiLike = Ref(a) .+′ b
-′(a::Perturbator,b::T) where T <: MultiLike = Ref(a) .-′ b
*′(a::Perturbator,b::T) where T <: MultiLike = Ref(a) .*′ b
/′(a::Perturbator,b::T) where T <: MultiLike = Ref(a) ./′ b

+′(a::T,b::Perturbator) where T<:Integer = round(T,a + b())
-′(a::T,b::Perturbator) where T<:Integer = round(T,a - b())
*′(a::T,b::Perturbator) where T<:Integer = round(T,a * b())
/′(a::T,b::Perturbator) where T<:Integer = round(T,a / b())

+′(a::Perturbator,b::T) where T<:Integer = round(T,a() + b)
-′(a::Perturbator,b::T) where T<:Integer = round(T,a() - b)
*′(a::Perturbator,b::T) where T<:Integer = round(T,a() * b)
/′(a::Perturbator,b::T) where T<:Integer = round(T,a() / b)

```

what i would like is to naturally operate on these object via primed operators, but this type hierarchy has become ridiculous, is there a way to shorten it and make it manageable?

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [June 22, 2020, 10:32pm UTC](https://discourse.julialang.org/t/best-way-to-express-this-algebra-between-types/41891/2 "2020-06-22T22:32:45Z")

</div>

A bit of metaprogramming at least will save you repeat everything for the four operators:

```julia
for op in (:+, :-, :*, :/)
    opp = Symbol(op, "′")
    @eval $opp(a, b) = $op(a, b)
    @eval $opp(a::T, b) where T <: MultiLike = $opp.(a, b)
    @eval $opp(a, b::T) where T <: MultiLike = $opp.(a, b)
    @eval $opp(a::T, b) where T <: Integer = round(T, $op(a, b))
    @eval $opp(a, b::T) where T <: Integer = round(T, $op(a, b))
    @eval $opp(a, b::Perturbator) = $opp(a, b())
    @eval $opp(a::Perturbator, b) = $opp(a(), b)
    @eval $opp(a::T, b::Perturbator) where T <: MulitLike = $opp.(a, Ref(b))
    @eval $opp(a::Perturbator, b::T) where T <: MultiLike = $opp.(Ref(a), b)
    @eval $opp(a::T, b::Perturbator) where T <: Integer = round(T, $op(a, b()))
    @eval $opp(a::Perturbator, b::T) where T <: Integer = round(T, $op(a(), b))
end

```
