Hi,
I was confused by the dispatch behavior with a hierarchy of types with (restricted) type parameters. Now I want to know if I understand correctly why the following does not work as I initially expected:
1st Example
Suppose, I have a type hierarchy
abstract type SuperRestricted{A<:Real} end
struct SubFree{A} <: SuperRestricted{A} end
In the definition of SubFree
i did not restrict A
out of laziness first. And as expected, something as SubFree{Complex}
will result in a TypeError
.
Next I wanted a method to dispatch for every subtype of SuperRestricted
:
func = ( x :: Type{<:SuperRestricted} ) -> println("Success.")
It works for func(SuperRestricted)
but not for func(SubFree)
because – to my surprise – SubFree <: SuperRestricted
is false
.
However, for
struct SubRestricted{A<:Real} <: SuperRestricted{A} end
we have SubRestricted <: SuperRestricted
and func(SubRestricted)
works.
2nd Example
Upon further experimentation I found that
abstract type SuperFree{A} end
struct SubFree{A} <: SuperFree{A} end
struct SubRestricted{A <: Real} <: SuperFree{A} end
SubFree <: SuperFree # true
SubRestricted <: SuperFree # true
Suspected Explanation(?)
In the first example, SuperRestricted{A<:Real}
describes a set of types where A
must be real.
Just from the definition of SubFree{A}
it seems that for this subtype A
might be anything and hence the set of types described by SubFree
are not a subset of the types SuperRestricted
in the mathematical sense. In constracst, SubRestricted{A<:Real}
is really a subset of types.
Likewise, in the second example, SuperFree{A}
does not put any bounds on A
and that is why subtypes can restrict it or not and truly remain subtypes.
Is that roughly correct?
In retrospect (and with these descriptive type names) it seems logical. I was confused first, because I thought that inheriting from a restricted type would make the subtype automatically restricted as well and the TypeError from SubFree{Complex}
in the first example somewhat confirmed me in this assumption.