# Dispatch on decorated (sub)types

**URL:** <https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396>\
**Category:** General Usage\
**Created:** [June 18, 2019, 9:28am UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396 "2019-06-18T09:28:34Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [June 18, 2019, 9:28am UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/1 "2019-06-18T09:28:34Z")

</div>

I was just wondering on how one could do multiple dispatch when using a decorator pattern and subtypes.

Imagine the following example

```julia
abstract type A end
struct A1 <: A
    c::Int
end
struct A2 <: A
    c::Float64
end
struct decoA{B <: A} <: A
   a::A
   name::String
end
decoA(a::B, s) where {B <: A} = decoA{B}(a,s)

```

basically this leads to 4 possible types

```julia
a1 = A1(1)
a2 = A2(1.)
a3 = decoA(a1,"Hi.")
a4 = decoA(a2,"Moin.")

```

with method dispatch on the first two I would write something (don’t mind the logic, it’s merely to illustrate the dispatch question)

```julia
f(a::A1) = A1(a.c*2)
f(a::A2) = A2(a.c/2)

```

then you get

```julia
julia> f(a1)
A1(2)
julia> f(a2)
A2(0.5)

```

now to the question: I would like to implement `f` also for the deco-cases, such that  
`f(a3)` is the same as `decoA(f(a1),"Hi.")` and `f(a4)` is the same as `decoA(f(a2),"Moin.")`,  
so to a certain extend, that `f` and `decoA`interact in a quite transparent way.

What’s the most elegant way to achieve such a dispatch with decorator pattern based types?

**Edit** : I actually found the answer to my MWE myself, it’s `f(a::decoA{T}) where {T <: A) = decoA(f(a.a),a.name)`

but that was merely due to my too simple MWE.

I would like to have an easy dispatch for all types `A1, decoA{A1}, decoB{A1}`, where `decoB` is similar to `decoA`, i.e. also with one parameter type and still a subtype of `A`, Can something like that be made with dispatch?

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [June 18, 2019, 6:35pm UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/2 "2019-06-18T18:35:02Z")

</div>

Not sure I understood the full extent of your question, but maybe something like this suits your needs.

```julia
abstract type A end
struct A1 <: A
    c::Int
end
struct A2 <: A
    c::Float64
end

# intermediate superclass for all decorators
abstract type DecoA <: A end

# each decorator has its own additions...
struct NamedA{T <: A} <: DecoA
   a::T # <-- this is what you meant, right? (instead of "a::A")
   name::String
end
# ... which can be retrieved using a specific method
decoration(x::NamedA) = x.name

# same for a second decorator
struct IndexedA{T <: A} <: DecoA
    a::T
    index::Int
end
decoration(x::IndexedA) = x.index

# Specific methods for bare, concrete `A` subtypes
f(a::A1) = A1(a.c*2)
f(a::A2) = A2(a.c/2)

# One method for all decorated `A` subtypes
f(x::T) where {T<:DecoA} = T(f(x.a), decoration(x))

```

```julia
julia> a1 = A1(1);
julia> a2 = A2(1.);
julia> a3 = NamedA(a1,"Hi.");
julia> a4 = NamedA(a2,"Moin.");
julia> a5 = IndexedA(a1, 42);
julia> for a in (a1, a2, a3, a4, a5)
           println("a = $a \t f(a) = $(f(a))")
       end
a = A1(1) f(a) = A1(2)
a = A2(1.0) f(a) = A2(0.5)
a = NamedA{A1}(A1(1), "Hi.") f(a) = NamedA{A1}(A1(2), "Hi.")
a = NamedA{A2}(A2(1.0), "Moin.") f(a) = NamedA{A2}(A2(0.5), "Moin.")
a = IndexedA{A1}(A1(1), 42) f(a) = IndexedA{A1}(A1(2), 42)

```

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [June 19, 2019, 7:15am UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/3 "2019-06-19T07:15:00Z")

</div>

Retrieving the information with a specific function is quite neat. And sorry for the confusion, maybe I was not yet sure what I want myself. That’s why I tried to extend my question already. So for the initial part, your answer is very neat, I think I am looking for a function, let’s say `g` that dispatches on the undecorated type even for (eventually multiple) decorators.

with your system maybe something like

- `g(a1)` should print `"I work like A1 and I am an A1"`
- `g(a2)` should ptint `"I do something different and I am an A2"`
- `g(a3)` should print `"I work like A1 and I am an NamedA{A1}(A1(2), "Hi.")`  
and so on but also for `a6 = IndexedA(a3, 23)` I would like to have `I work like A1 and I am an IndexedA{NamedA{A1}}(NamedA{A1}(A1(2), "Hi."), 23)"`.

I think my main problem is then actually this double-encapsualed matching – and yes I was not aware, that that was my problem in the beginning 😉 so sorry for the confusion concerning the initial topic.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [June 19, 2019, 9:48am UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/4 "2019-06-19T09:48:25Z")

</div>

> [@kellertuer](#):
>
> I think my main problem is then actually this double-encapsualed matching – and yes I was not aware, that that was my problem in the beginning 😉 so sorry for the confusion concerning the initial topic.

No worries. I’m still not sure I get what you want, but these are interesting questions, well worth the time we spend thinking about them IMO.

Would that cover what you were thinking about?

```julia-auto
abstract type A end
struct A1 <: A
    c::Int
end
struct A2 <: A
    c::Float64
end

# intermediate superclass for all decorators
abstract type DecoA <: A end

# each decorator has its own additions
struct NamedA{T <: A} <: DecoA
   a::T # <-- this is what you meant, right? (instead of "a::A")
   name::String
end

struct IndexedA{T <: A} <: DecoA
    a::T
    index::Int
end

# Behaviour of bare, concrete `A` subtypes
f(a::A1) = "A1 behaviour ($(a.c*2))"
f(a::A2) = "A2 behaviour ($(a.c/2))"
f(a::DecoA) = f(a.a)

# Global behaviour of decorations
decoration(a) = ""
decoration(a::DecoA) = decoration_(a) * decoration(a.a)

# Specific behaviour of decorations
decoration_(a::NamedA) = " with name $(a.name)"
decoration_(a::IndexedA) = " with index $(a.index)"

# Combination of base behaviour and decoration
g(a::T) where {T<:A} = f(a) * decoration(a) * " and I'm an $T"

# Test
a1 = A1(1);
a2 = A2(1.);
a3 = NamedA(a1,"Hi.");
a4 = NamedA(a2,"Moin.");
a5 = IndexedA(a1, 42);
a6 = IndexedA(a3, 23);
for a in (a1, a2, a3, a4, a5, a6)
    println("a = $a \t $(g(a))")
end

```

```julia-auto
a = A1(1) A1 behaviour (2) and I'm an A1
a = A2(1.0) A2 behaviour (0.5) and I'm an A2
a = NamedA{A1}(A1(1), "Hi") A1 behaviour (2) with name Hi and I'm an NamedA{A1}                                                                                 
a = NamedA{A2}(A2(1.0), "Moin") A2 behaviour (0.5) with name Moin and I'm an NamedA{A2}                                                                     
a = IndexedA{A1}(A1(1), 42) A1 behaviour (2) with index 42 and I'm an IndexedA{A1}                                                                              
a = IndexedA{NamedA{A1}}(NamedA{A1}(A1(1), "Hi"), 23) 
                                 A1 behaviour (2) with index 23 with name Hi and I'm an IndexedA{NamedA{A1}}                                 

```

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [June 19, 2019, 3:11pm UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/5 "2019-06-19T15:11:30Z")

</div>

Ah, that’s again very neat! Thanks I learned quite a lot. I think I also got to the last thing that I am still thinking about, whether it’s still possible.  
With just the first few lines

```julia
abstract type A end
struct A1 <: A
    c::Int
end
struct A2 <: A
    c::Float64
end

```

My original function `g` (before starting decorating) had three dispatch choices

```julia
g(a::A1) = "Inty"
g(a::A2) = "Floaty"
g(a::T) where {T <: A} = error("You might want to consider implementing g for your A-subtype $(T).")

```

merely to help users, that implement something that they just missed `g` when implementing a certain interface (consisting maybe of 3 or 4 functions within a framework working o `A`subtypes).

This last line is the only one I miss, because `g` now can not do that anymore. That’s why I asked for a signature that dispatches on anything decorating with most inner type `A1`, with that I could say, that for any type (undecorated) I could provide again an error for `g`.

Long story short – I think only `f` can now take over this error message, because with its implicit “undecoration” for `a::DecoA` inputs (something I learned in this thread – and one could also do this with `Traits` instead of a common decotype).

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [June 19, 2019, 3:19pm UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/6 "2019-06-19T15:19:42Z")

</div>

> [@kellertuer](#):
>
> I think only `f` can now take over this error message

Why is that a problem? `f` is the function that new `A` bare subtypes have to implement anyway, isn’t it? Likewise, `decoration_` is the function for which new decorators should implement a method, and the default error message (missing method) can be overriden with a more user-friendly one.

Or am I missing something?

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [June 19, 2019, 3:33pm UTC](https://discourse.julialang.org/t/dispatch-on-decorated-sub-types/25396/7 "2019-06-19T15:33:03Z")

</div>

I don’t know why that was a problem for past-me, maybe I was too stuck in a strict dispatch idea.  
And yes, with `dectoration_` one could also generate a beautiful error message. Avoiding a just `missing method`-message and provide more hints what’s actually to do for fixing the error is what I am aiming for there.
