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.