Three confusing things are happening here:
- In Julia, types are values and values are types. We can’t draw clear distinctions between them. All types are values that are instances of
DataType
(well, almostUnion{}
strikes again!). But that means we couldn’t dispatch on a type because they are allDataType
s. So… Type
is a unique, special-cased type that allows for sharpening type fields.It is extremely important to dispatch and such, but it does cause a violation of the type system’s rules which–I believe–leads to the friction you’re experiencing. Specifically, while each type is an instance of the concrete type. Edit: see my comment below, this is not correct.DataType
, it is ALSO an instance of the concrete typeType{T}
(for some T). This is normally impossible (an instance can only be of one concrete type)Any
is the top of that type system. By definition, all types are subtypes ofAny
. ButAny
is also an instance ofDataType
because types are just values. Not too weird, but it does yield funny things like:
julia> typeof(Any) <: Any
true
Your taxonomy of types doesn’t work because it presupposes that there are different kinds of types. There are not. Julia has a type system which describes the super- and sub-type relationships between all types, without drawing distinctions between those types.
The “issue” that
Isn’t an issue for the soundness of the system. Walking through it:
Int isa Type{Int}
– as we’ve addressed, this is the odd case.Type{Int} <: DataType
– This is true because in a deep wayType{T} where T === DataType
, so this is like sayingType{Int} <: Type
which is true.DataType <: Type
– All types, includingDataType
, areType
s. Specifically,DataType isa Type{DataType}
.Type <: Any
this is axiomatic to the Julia type system.
I also don’t understand where your claim that:
comes from in the docs? Can you clarify the contradiction you’re seeing? Based on my reading of your code example above that claim, I don’t see an issue.
DataType
is the type of all types. SoDataType
(being a type) is an instance ofDataType
.- Also,
T <: T
is true for allT
whereT
is a type. SoDataType <: DataType
must be true. DataType
is an unparametrized type that has instances (all the other types), so it behaves like any concrete type.
Edit: Thinking about this more – I’m actually wondering if it’s more like DataType
is the real special case because it is basically Type{T} where T
in a trenchcoat pretending to be concrete even though it’s a UnionAll
? I don’t know. Someone who knows more Type Theory will have to weigh in there