What is the type of #undef

struct MMX
           x
           MMX() = new()
       end

t = MMX()
> MMX(#undef)
typeof(t.x)

Basically I am asking what is the type of field x in this case?

1 Like

Weird but interesting question…

julia> typeof(undef)

UndefInitializer

julia> typeof(UndefInitializer)
DataType

dump(undef)
UndefInitializer array initializer with undefined values

show(undef)
array initializer with undefined values

https://github.com/JuliaLang/julia/blob/0b80774b9f0a517f12714e30808915e99fd916ff/base/boot.jl#L402

Apparently it’s a quintessential empty struct!

1 Like
julia> struct OO
       x
       end

julia> OO(undef)
OO(array initializer with undefined values)

julia> t = ans
OO(array initializer with undefined values)

julia> t.x
array initializer with undefined values

I don’t think what you say is quite right because in the former case

struct MMX
           x
           MMX() = new()
       end

t = MMX()
julia> t.x
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(::Any, ::Symbol) at ./Base.jl:20

I’d say it’s Union{}.

If so, how can I instantiate Union{} or I can ask this question another way, How can I create and undefined reference object if something like that exists.

You can’t create an undefined reference object, but that is exactly the point. It stands for a stack-allocated object, that has not been defined yet. A classic use case is for vectors, e.g. Vector{SomeType}(undef, n), whose values will be overwritten anyways, so there’s no need to fill them with a value. undef is just a singleton object signifying, that a vector or a mutable struct does not need to be initialized. If SomeType is heap-allocated, on the other hand, it will just be some random value that has been in this location in memory, so this shouldn’t usually be relied upon. The reason this works for your type MMX is that x is of type Any, which means it is boxed, so it can be #undef.

2 Likes

If you agree that any “thing” inside of a Vector{T} is of type T, then my argument follows from the observation

julia> resize!(Union{}[], 1)
1-element Array{Union{},1}:
 #undef

It is also compatible with that Union{} <: T holds for any type T. So you can “put” #undef inside of any arrays:

julia> Union{} <: Some
true

julia> resize!(Some[], 1)
1-element Array{Some,1}:
 #undef

julia> Base._return_type(getindex, (Vector{Some}, Int))
Some

julia> ans == Union{Union{}, Some}
true

(Everything I said here just “kind of” makes sense.)

Generally, values have types, and for your example there is no value yet (hence #undef). So t.x will raise an error, and typeof(t.x) cannot be executed as such.

So, in a sense, the question is meaningless. #undef was introduced precisely to signal this: it is not a value per se, just a way of signaling that there is no value.

1 Like

you can think of the type as Int