Skip to content

redesign typeof(::Type) #29368

Open
Open
@JeffBezanson

Description

@JeffBezanson

A type in Julia takes one of four forms: DataType, Union, UnionAll, or Bottom. These are represented as Julia structs, distinguished by ordinary type tags for each of the four. This arrangement creates some subtle problems.

Types can be compared two ways: structurally (===, "looks the same when printed") and semantically (==, what set of values does it represent). For example Int == Union{Int,Int} but they have different structures (actually we normalize the union to just Int, but in theory such a union type can exist). The representation of a type, which is what you currently get from typeof, only involves its structure and not semantics.

The problem is that the type system prefers to compare types semantically. For example A{X} <: A{Y} iff X == Y (semantic comparison). However it is also possible to dispatch on type representations. For example

f(t::DataType) = 0
f(t::Union) = 1
g(::Type{T}) where {T} = f(T)

A call like g(Int) does not have a clear answer --- strictly speaking we only know that T == Int, not its representation. We currently have to use various hacks to get around this. One such hack is that inference is suboptimal in cases like this:

foo(f) = Ref((f,))
@code_typed foo(Complex) # => RefValue{_1} where _1

A related issue is that types like DataType and Type{Int} have an overly-complex subtype and specificity relationship: one is not a subtype of the other, but their intersection is non-empty, and we're not able to accurately represent that intersection. For various reasons (including backwards compatibility) subtyping currently gets this wrong on purpose, making Type{Int} <: DataType true.

I've come to think we'd be better off getting rid of DataType et. al., and not using type tags to identify type representations. Instead, for instance, we could make typeof(t) give Type for every type, and you'd have to look at fields to determine whether you have a Union, UnionAll, etc.

cc @vtjnash @jrevels

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingThis change will break codetypes and dispatchTypes, subtyping and method dispatch

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions