# How to subtype a type alias?

**URL:** <https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050>\
**Category:** General Usage\
**Tags:** traits\
**Created:** [May 9, 2019, 9:49pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050 "2019-05-09T21:49:05Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [May 9, 2019, 9:49pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/1 "2019-05-09T21:49:05Z")

</div>

Hello everyone,

I have a struct:

```julia
struct MyType
    data :: Int
end

```

Now I want to create a vector of such structs:

```julia
const MyVector = Vector{MyType}

```

This works fine because I can make methods that dispatch on MyVector.

```julia
myfunction(::MyVector) = "some vector"

```

And it is very easy to create instances of that vector:

```julia
myvector = [MyType(1), MyType(2)]

```

My problem is that I would like to create an abstract type of which MyVector is subtype.  
I don’t see how to do that.  
I could, however make a wrapper type

```julia
abstract type AbstractStructure end
struct MyVector2 <: AbstractStructure
    data :: Vector{MyType}
end

```

But then to construct an instance I have to do

```julia
myvector2 = MyVector2([MyType(1), MyType(2)])

```

which I find a bit clumsy.  
Is there a way to make

```julia
myvector2 = [MyType(1), MyType(2)]

```

where

```julia
typeof(myvector2)<: AbstractStructure
true

```

?  
Many thanks in advance,  
Olivier

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 9, 2019, 11:11pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/2 "2019-05-09T23:11:22Z")

</div>

What did you want this ability for? Is it for dispatch? If so, one avenue to get the behaviour you want (if not the syntax) is to use so-called trait based dispatch:

```julia
struct MyType
    data :: Int
end

const MyVector = Vector{MyType}
const MyMatrix = Matrix{MyType}

struct IsMyArray{T} end
struct Not{T} end 

ismyarray(::T) where {T} = Not{IsMyArray{T}}
ismyarray(::MyVector) = IsMyArray{MyVector}
ismyarray(::MyMatrix) = IsMyArray{MyMatrix}

f(x) = f(ismyarray(x), x)
f(::Type{IsMyArray{T}}, x) where {T} = "$T is one of my arrays"
f(::Type{Not{IsMyArray{T}}}, x) where {T} = "$T is not one of my arrays"

```

```julia
julia> f([MyType(1), MyType(2)])
 "Array{MyType,1} is one of my arrays"

julia> f([MyType(1), 2])
 "Array{Any,1} is not one of my arrays"

 julia> f([MyType(1); MyType(2)])
 "Array{MyType,1} is one of my arrays"

 julia> f([MyType(1) MyType(2);
           MyType(3) MyType(4)])
 "Array{MyType,2} is one of my arrays"

```

What is being done here is that we’ve invented a ‘trait’, `IsMyArray{T}` that is kinda like an abstract type but it doesn’t actually exist in the formal type hierarchy, but using the function `ismyarray`, we can still dispatch on the ‘members’ of this trait which in this case are `MyVector` and `MyArray`.

What I like about this approach is that it’s very flexible and can be extended by others downstream of you. You can even use it to unify objects from unrelated type heirarchies. Ie. you could make `NTuple{N, MyType} where {N}` a member of `IsMyArray` if you like, even though `NTuple` isn’t an `AbstractArray` and is not a type that you own. What I don’t like is that it’s a bit syntactically burdensome to set up.

There’s a package called [SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl) which attempts to automate / smooth this process but I often find it a bit more confusing than just writing the trait by hand. Your milage may vary.

---

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [May 10, 2019, 9:09am UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/3 "2019-05-10T09:09:38Z")

</div>

Hi,  
Thanks a lot for this answer. I never thought about using traits in this case.  
I’m very ignorant about traits though. Is it possible to create a supertype to the trait somehow?

With the solution I’m using now:

```julia
const MyVector = Vector{MyType}

```

I can already dispatch. So that is not really the issue.  
What I need is to be able to define different structures which are subtypes of AbstractStructure in order to be able to write a generic function.

I have different structures:

```julia
abstract type AbstractStructure end

struct Bulk <: AbstractStructure end
struct MultiLayer <: Abstractstructure end

```

I just want to write

```julia
function absorption(structure :: AbstractStructure)
    r= reflection(structure)
    t= transmission(structure)
   return 1-r-t
end

```

where I have the methods

```julia
reflection(a :: Bulk) = 0.1
reflection(a :: MultiLayer) = 0.2
transmission(a :: Bulk) = 0.2
transmission(a :: MultiLayer) = 0.3

```

In my case MultiLayer is of the type Vector{MyType} which I don’t see how to make it subtype of AbstractStructure such as to keep absorption function generic.

To solve this I see 2 (3?) approaches

- Using const MultiLayer = Vector{MyType} and create an union type Union{Bulk,MultiLayer}, but this is not easily extendable and I have to modify the union type.
- Wrapping Vector{MyType} in the MultiLayer struct but then I don’t see how I can construct my vector like [MyType(1), MyType(2)]
- Using traits, but then I have the same problem as in option 1, or maybe not?

So is it possible to create a vector const MultiLayer = Vector{MyType} for which?

```julia
myvector2 = [MyType(1), MyType(2)]
typeof(myvector2)<: AbstractStructure
true

```

Thanks again,

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 10, 2019, 6:49pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/4 "2019-05-10T18:49:44Z")

</div>

> Is it possible to create a supertype to the trait somehow?

A trait already is _like_ a supertype. So in the example I showed above, we have the trait `IsMyArray{T}` and we can add members to it by just adding methods to the `ismyarray` function.

I still find your example quite unclear, and from what you say I suspect you can get away with something much simpler, but I’m going to assume the actual functionality you need is something like an abstract type. In that case, I’ll try again to give an example that might answer your question using traits.

First, lets define our types and aliases:

```julia
struct Bulk end

struct MyType
    data::Float64
end

const MultiLayer = Vector{MyType}

```

Now, lets define a trait called `Structure`, and make a function `has_structure_trait` that can decide if a given type is a member of our trait. For now, we’ll only register `Bulk` and `MultiLayer` as members, but we can add more whenever we like.

```julia
struct Structure{T} end
struct Not{T} end 

has_structure_trait(::T) where {T} = Not{Structure{T}}()
has_structure_trait(::MultiLayer) = Structure{MultiLayer}()
has_structure_trait(::Bulk) = Structure{Bulk}()

```

Now we can define our functions. The main difference from regular dispatch rules is that we’ll need functions that send their input to `has_structure_trait` to decide if they’re kosher to dispatch on:

```julia
absorption(structure) = absorption(has_structure_trait(structure), structure)
function absorption(::Structure{T}, structure) where {T}
    r= reflection(structure)
    t= transmission(structure)
   return 1-r-t
end

reflection(s) = reflection(has_structure_trait(s), s)
reflection(::Structure{Bulk}, s::Bulk) = 0.1
reflection(::Structure{MultiLayer}, s::MultiLayer) = sum(x -> (x.data), s)

transmission(s) = transmission(has_structure_trait(s), s)
transmission(::Structure{Bulk}, s::Bulk) = 0.2
transmission(::Structure{MultiLayer}, s::MultiLayer) = sum(x -> 2*(x.data), s)

```

Now lets test it at the REPL.

```julia
julia> absorption(Bulk())
0.7

julia> absorption([MyType(0.1), MyType(0.2)])
0.09999999999999987

julia> absorption([1, 2])
ERROR: MethodError: no method matching absorption(::Not{HasStructureTrait{Array{Int64,1}}}, ::Array{Int64,1})
Closest candidates are:
  absorption(::HasStructureTrait{T}, ::T) where T at REPL[10]:2
  absorption(::Any) at REPL[9]:1
Stacktrace:
 [1] absorption(::Array{Int64,1}) at ./REPL[9]:1
 [2] top-level scope at none:0

```

If we want to improve that error message, we can do this:

```julia
julia> absorption(::Not{Structure{T}}, x::T) where {T} = throw("$T does not have the Structure Trait.")
absorption (generic function with 4 methods)

julia> absorption([1,2])
ERROR: "Array{Int64,1} does not have the Structure Trait."
Stacktrace:
 [1] absorption(::Not{HasStructureTrait{Array{Int64,1}}}, ::Array{Int64,1}) at ./REPL[19]:1
 [2] absorption(::Array{Int64,1}) at ./REPL[9]:1
 [3] top-level scope at none:0

```

* * *

So what we’ve done is made a trait called `Structure{T}` and we can add members to it using the `has_structure_trait` function. That can be done at any time and is very extensible. It is analogous to defining an abstract type, except it has fewer restrictions, and we can even do it to types we don’t own.

The downside is that we have to introduce methods like

```julia
absorption(structure) = absorption(has_structure_trait(structure), structure)

```

which decide if a certain structure gets passed on to

```julia
absorption(::Structure{T}, structure::T) where {T}

```

and this can add a fair amount of verbosity as you can see.

Basically the way to think about traits is that we are hacking the dispatch system so that we can just write a function `has_structure_trait` which decides what method gets used on a certain piece of data instead of the normal rules from the type system.

* * *

**Edits:**  
I’ve included some clarity improvements and the suggestion from @Tamas_Papp to dispatch on values instead of types.

---

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [May 10, 2019, 11:09pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/5 "2019-05-10T23:09:29Z")

</div>

Thanks a lot for taking the time to explain this in so much detail.  
But I think I need some time to digest it 😉

> [@Mason](#):
>
> I still find your example quite unclear, and from what you say I suspect you can get away with something much simpler,

I’m sorry if I was not totally clear.  
I’m not sure if I can explain it much better though.

Would you mind to give a hint of what a simpler solution could be?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 11, 2019, 12:31am UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/6 "2019-05-11T00:31:14Z")

</div>

> [@Olivier\_Merchiers](#):
>
> Thanks a lot for taking the time to explain this in so much detail.  
> But I think I need some time to digest it 😉

No worries, traits are something I’ve known vaguely about for a while but never really spent the time to use or implement them, so this was an instructive exercise for me as well.

> [@Olivier\_Merchiers](#):
>
> I’m sorry if I was not totally clear.  
> I’m not sure if I can explain it much better though.
> 
> Would you mind to give a hint of what a simpler solution could be?

I guess I’m just not sure if you really need the power of traits or even abstract types here, but its hard to know without seeing the larger context of what you’re actually tying to achieve. For instance, in the example you gave me, there’s no real reason why `absorption` needs some sort of restricted dispatch. Ie. your example would work fine if you just did

```julia
struct MyType
    data :: Int
end
const MultiLayer = Vector{MyType}

struct Bulk end

function absorption(structure) # Note that I've remove the type parameter here
    r = reflection(structure)
    t = transmission(structure)
   return 1-r-t
end

reflection(a::Bulk) = 0.1
reflection(a::MultiLayer) = 0.2
transmission(a::Bulk) = 0.2
transmission(a::MultiLayer) = 0.3

```

Now everything works and there’s no need for abstract types or traits. The function `absorption` will fail on any type other than `Bulk` or `MultiLayer` because `reflection` and `transmission` don’t have methods for any other types.

Of course, such an approach could fall apart depending on what you’re actually trying to do in practice.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 11, 2019, 2:07am UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/7 "2019-05-11T02:07:28Z")

</div>

Also, let me know if there’s something in the second example that’s still unclear to you. I can try and expand on that.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 11, 2019, 6:29am UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/8 "2019-05-11T06:29:21Z")

</div>

> [@Mason](#):
>
> ```julia
> has_structure_trait(::T) where {T} = Not{HasStructureTrait{T}}
> 
> ```

Nice example, but not that another style (possibly [more commonly used](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-confusion-about-whether-something-is-an-instance-or-a-type-1)) is returning _values, not types_, and dispatch accordingly, eg

```julia
has_structure_trait(::T) where {T} = Not{HasStructureTrait{T}}()

function absorption(::HasStructureTrait{T}, structure) where {T}
    ...

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 11, 2019, 10:14pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/9 "2019-05-11T22:14:11Z")

</div>

Good point. I’ll update my code above with that and a couple other legibility improvements.

---

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [May 12, 2019, 9:38am UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/10 "2019-05-12T09:38:07Z")

</div>

Thanks again for your detailed explanation.  
And indeed, I didn’t realize I don’t really need an abstract type!  
That is quite an eye opener.  
I have to check my code to see if I can totally get rid of it.

Just a small question related to

```julia
has_structure_trait(::T) where {T} = Not{HasStructureTrait{T}}

```

Why couldn’t you just do?

```julia
has_structure_trait(::T) where {T} = Not{T}

```

This seems to work also.

Many thanks again!

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 12, 2019, 5:59pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/11 "2019-05-12T17:59:50Z")

</div>

> [@Olivier\_Merchiers](#):
>
> Just a small question related to
> 
> ```julia
> has_structure_trait(::T) where {T} = Not{HasStructureTrait{T}}
> 
> ```
> 
> Why couldn’t you just do?
> 
> ```julia
> has_structure_trait(::T) where {T} = Not{T}
> 
> ```
> 
> This seems to work also.
> 
> Many thanks again!

The `Not{HasStructureTrait{T}}` is important for if you have multiple traits laying around and you want to distinguish between them. Like for instance, imagine using fallback methods

```julia
f(::Not{HasStructureTrait{T}}, x::T) where {T} = g(x)
f(::Not{HasSomeOtherTrait{T}}, x::T) where {T} = h(x) 

```

---

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [May 12, 2019, 9:33pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/12 "2019-05-12T21:33:37Z")

</div>

Ok, I see.  
Thanks!

---

<div class="post-metadata">

**Author:** ![doit](https://avatars.discourse-cdn.com/v4/letter/d/9dc877/32.png) [@doit](https://discourse.julialang.org/u/doit)\
**Post date:** [September 27, 2019, 8:15am UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/13 "2019-09-27T08:15:11Z")

</div>

I assume what @Olivier_Merchiers meant was something similar to the effect that in Base (array.jl) `Matrix` is defined on line 66 as

```julia
const Matrix{T} = Array{T,2}

```

where following type dependency is `true`

```julia
Matrix{T} <: AbstractMatrix{T}

```

without it anywhere being explicitly defined at that particular point, but indirectly implying a hidden hierarchy. It seems to pop up out of nowhere, which greatly confused me at first.  
However, just a bit above on line 31 we have

```julia
const AbstractMatrix{T} = AbstractArray{T,2}

```

which then results in the type dependancy! This comes down to the very simple fact that `Array{T,2} <: AbstractArray{T,2}`, which `Matrix{T} <: AbstractMatrix{T}` would evaluate to.

Thus, if you have

```julia
struct MyType
    data :: Int
end

```

and

```julia
const MyVector = Vector{MyType}

```

you can simply define

```julia
const AbstractMyVector{T<:MyType} = AbstractVector{T}

```

and now `MyVector <: AbstractMyVector`.

**BUT** I don’t see the point in doing that to solve your problem (which you already solved anyway). You would then be dispatching on `AbstractVector` where you restricted `T<:MyType`. You can do that without the alias and you couldn’t extend this hierarchy in any meaningful way anyway. (I assume you wanted a supertype, which is not necessarily an AbstractVector.)

I even find these “parallel” or “shadow” hierarchies very confusing, because without looking into Base or maybe _help_ or quickly printing the “type” in REPL you never know which types are actual structs/types and which are simply aliases.

---

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [June 30, 2020, 9:42pm UTC](https://discourse.julialang.org/t/how-to-subtype-a-type-alias/24050/14 "2020-06-30T21:42:01Z")

</div>

Hi,

Sorry I just realized I never replied!  
Thanks a lot for this great explanation!
