rakesh a
rakesh a

Reputation: 587

Julia: Difference between Type and DataType

To me they seem to be the same. Since Type is of type DataType and vice-versa, how are they not equivalent? When should I use one versus the other?

> isa(DataType, Type)
true

> typeof(Type)
DataType

> isa(Type, DataType)
true

> typeof(DataType)
DataType

Upvotes: 15

Views: 2066

Answers (1)

mbauman
mbauman

Reputation: 31362

Type and DataType are themselves both types. And the type of most types is, as you've found, DataType. In this case, DataType is a subtype of the abstract Type:

julia> supertype(DataType)
Type{T}

julia> supertype(Type)
Any

julia> DataType <: Type
true

This means that anything that isa DataType will also be a Type — so many types in Julia are isa both. There are also other subtypes of Type, including Unions and TypeConstructors. This means that all types in julia will be of type Type, but even simple things like Vector won't be of type DataType.

Type is special. As you see above, it's parametric. This allows you to precisely specify the type of a specific type in question. So while every single type in Julia isa Type, only Int isa Type{Int}:

julia> isa(Int, Type{Int})
true

julia> isa(Float64, Type{Int})
false

julia> isa(Float64, Type)
true

This ability is special and unique to Type, and it's essential in allowing dispatch to be specified on a specific type. For example, many functions allow you to specify a type as their first argument.

f(x::Type{String}) = "string method, got $x"
f(x::Type{Number}) = "number method, got $x"

julia> f(String)
"string method, got String"

julia> f(Number)
"number method, got Number"

It's worth noting that Type{Number} is only the type of Number, and not the type of Int, even though Int <: Number! This is parametric invariance. To allow all subtypes of a particular abstract type, you can use a function parameter:

julia> f(Int)
ERROR: MethodError: no method matching f(::Type{Int64})

julia> f{T<:Integer}(::Type{T}) = "integer method, got $T"
f (generic function with 3 methods)

julia> f(Int)
"integer method, got Int64"

The ability to capture the specific type in question as a function parameter is powerful and frequently used. Note that I didn't even need to specify an argument name — the only thing that matters in this case is the parameter within Type{}.


So that was a pretty long explanation for what's really a pretty short answer: You typically don't want to use DataType, since it won't cover all types in Julia. Instead you should use Type to describe the type of any or all types. Use Type{T} when you want to describe the type of T in particular.

Upvotes: 12

Related Questions