# Work around invariance

**URL:** <https://discourse.julialang.org/t/work-around-invariance/1205>\
**Category:** General Usage\
**Tags:** question\
**Created:** [December 29, 2016, 4:54pm UTC](https://discourse.julialang.org/t/work-around-invariance/1205 "2016-12-29T16:54:48Z")\
**Posts on this page:** 8\
**Page:** 1

<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:** [December 29, 2016, 4:54pm UTC](https://discourse.julialang.org/t/work-around-invariance/1205/1 "2016-12-29T16:54:48Z")

</div>

I am working with a family of models, which have certain properties, lets call them `statenames` and `obsnames`. Many of these are shared between models, so it would be nice to reuse them. Models are mapped to types in my code. I would like to query these properties **for the types**.

So I thought I would use abstract types like this:

```julia
abstract AbstractModel{S,O}
abstract FiveStateModel
statenames(::Type{FiveStateModel}) = (:NL,:NM,:NH,:EM,:EH)
abstract ObservedEUH
obsnames(::Type{ObservedEUH}) = (:E,:U,:H)

immutable SimpleModel1{T <: Real} <: AbstractModel{FiveStateModel, ObservedEUH}
    x::T
    y::T
end

```

Now I want

```julia
statenames(SimpleModel1)

```

to return `(:NL,:NM,:NH,:EM,:EH)`. If types were covariant, I could use

```julia
statenames{S,O}(::Type{AbstractModel{S,O}}) = statenames(S)
obsnames{S,O}(::Type{AbstractModel{S,O}}) = obsnames(O)

```

but since they are not, I am using

```julia
statenames{S,O}(::AbstractModel{S,O}) = statenames(S)
obsnames{S,O}(::AbstractModel{S,O}) = obsnames(O)

```

and have to instantiate a `SimpleModel1`, eg

```julia
statenames(SimpleModel1(1.0,1.0))

```

Is there a workaround that would allow me to solve this in type-space?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 29, 2016, 4:56pm UTC](https://discourse.julialang.org/t/work-around-invariance/1205/2 "2016-12-29T16:56:51Z")

</div>

> [@Tamas\_Papp](#):
>
> Is there a workaround that would allow me to solve this in type-space?

Traits. Put a trait on `SimpleModel1` and do trait dispatch instead. I would suggest using SimpleTraits.jl to make it easier.

Or just wait for v0.6. It looks like Jeff’s PR is going to make it and so I think that will fix the problem.

---

<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:** [December 29, 2016, 5:00pm UTC](https://discourse.julialang.org/t/work-around-invariance/1205/3 "2016-12-29T17:00:21Z")

</div>

Just out of curiosity, which PR is that?

---

<div class="post-metadata">

**Author:** ![Evizero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evizero/32/10118_2.png) [@Evizero](https://discourse.julialang.org/u/Evizero)\
**Post date:** [December 29, 2016, 5:04pm UTC](https://discourse.julialang.org/t/work-around-invariance/1205/4 "2016-12-29T17:04:57Z")

</div>

The following approach doesn’t always work, depending on if your subtypes leave the type-parameters of `AbstractModel` flexible. It looks like you don’t, however, so in your use-case this should do the trick:

```julia
# do these as you described
statenames{S,O}(::Type{AbstractModel{S,O}}) = statenames(S)
obsnames{S,O}(::Type{AbstractModel{S,O}}) = obsnames(O)

```

```nohighlight
julia> statenames{T<:AbstractModel}(::Type{T}) = statenames(supertype(T))
statenames (generic function with 3 methods)

julia> statenames(SimpleModel1)
(:NL,:NM,:NH,:EM,:EH)

```

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 29, 2016, 5:06pm UTC](https://discourse.julialang.org/t/work-around-invariance/1205/5 "2016-12-29T17:06:17Z")

</div>

> [@Tamas\_Papp](#):
>
> Just out of curiosity, which PR is that?

> <https://github.com/JuliaLang/julia/pull/18457>
>
> This implements the plan in #8974. It is now working well enough to build a syst…em image and get a REPL, albeit with inference disabled. I have some demos.
> 
> In the internals there are "only" three changes:
> \- Types are explicitly quantified by wrapping in \`UnionAll\` types, which have two fields: a TypeVar and a type body:
> 
> \`\`\`
> julia\> Array
> Array{T,N} where N where T
> \`\`\`
> \- \`Union\` types now have two fields, pointing to two types to union together (instead of an svec of types). This is just a representation change.
> \- There is a new algorithm for computing the subtype relation. It gives drastically more meaningful results, and will replace the code for subtype and intersection in jltypes.c with a significant net code deletion. Working examples:
> 
> \`\`\`
> julia\> Tuple{Union{Int,String}} \<: Union{Tuple{Int},Tuple{String}}
> true
> 
> julia\> NTuple \<: Tuple, Tuple \<: NTuple
> (true,false)
> \`\`\`
> 
> The second one is issue #18450.
> 
> UnionAll types nest arbitrarily, and the signatures of methods with static parameters are UnionAll types, so we now have "triangular" dispatch:
> 
> \`\`\`
> julia\> f{T\<:Real, A\<:AbstractArray{T}}(x::T, y::Vector{A}) = 0
> f (generic function with 1 method)
> 
> julia\> f(1.0f0, \[rand(4,4)\])
> ERROR: MethodError: no method matching f(::Float32, 
> in eval(::Module, ::Any) at ./boot.jl:235SYSTEM: show(lasterr) caused an error
> 
> julia\> f(1.0f0, \[rand(Float32, 4,4)\])
> 0
> \`\`\`
> 
> (Clearly showing the method error isn't working, but that should just be a matter of updating the showing and reflection code in Base.)
> 
> The next steps are to get inference working and then fully replace intersection and morespecific with implementations based on the new algorithm.
> 
> \*\*Edit:\*\* Fixes #19159 #18892 #18450 #18348 #17943 #16922 #13165 #12596 #11803 #8915 #8625 #6721 #2552

See the triangular dispatch example. With that extra level of dispatch control you should be able to do what you need.

---

<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:** [December 30, 2016, 9:13am UTC](https://discourse.julialang.org/t/work-around-invariance/1205/6 "2016-12-30T09:13:30Z")

</div>

I found that for my use case, I can simply do

```julia
# reuse these for various models
const OBSERVED_EUH = (:E, :U, :H)
const FIVE_STATES = (:NL,:NM,:NH,:EM,:EH)

# and for one specific model
statenames(::SimpleModel1) = FIVE_STATES
obsnames(::SimpleModel1) = OBSERVED_EUH

```

I guess the lesson is that not all information needs to be encoded in the type system.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 30, 2016, 9:18am UTC](https://discourse.julialang.org/t/work-around-invariance/1205/7 "2016-12-30T09:18:45Z")

</div>

> [@Tamas\_Papp](#):
>
> I guess the lesson is that not all information needs to be encoded in the type system.

Well, that’s still using the type system (via dispatch). It’s that not all information needs to be encoded as fields. In fact, using dispatches to hold information is precisely how traits are implemented, so this and traits are one and the same.

---

<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:** [December 30, 2016, 9:32am UTC](https://discourse.julialang.org/t/work-around-invariance/1205/8 "2016-12-30T09:32:56Z")

</div>

I admit that I am just learning about traits, but from most examples it seems that there is an extra level of indirection involved.
