What's a good way to get some value (doesn't matter what the value is) of a type `T` `where T`

I am writing some program that requires a value from a type T but it doesn’t matter what this type is.

Is there a generic way to get some value of type T for whatever T? Happy to accept T for isbits.

zero(T) would work for many types T

Forgot to mention, the default method is zero(T) for me. So nunbers are pretty much covered.

rand(T)?

Currently I have method a method

some_elm(x::N) where N <: Number = zero(x)
some_elm(s::String) = ""

etc

Also experimenting with

some_elm(::Type{T}) = T(0)

and also rand(Date) doesn’t work

thanks. but also tried T_T

How about Array{T}(undef, 0, 0)?

1 Like

Pretty good. I can live with it now even though it doesn’t work for all types.

Vector{Type}(undef, 1)[1]
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex(::Array{Type,1}, ::Int64) at ./array.jl:742
 [2] top-level scope at REPL[17]:1

One way is to change your program maybe so that it accepts a reference or a zero-dimensional array. Those can be constructed without any actual values:

julia> Ref{Int}()
Base.RefValue{Int64}(0)

julia> Ref{String}()
Base.RefValue{String}(#undef)

julia> Array{DataType,0}(undef)
0-dimensional Array{DataType,0}:
#undef
3 Likes

An alternative solution to Array{T} is

struct SomeValue{T}
    value::T
    SomeValue{T}() where T = new{T}()
end

function somevalue(T::Type)
    s = SomeValue{T}()
    return isdefined(s, :value) ? Some(s.value) : nothing
end

(you can also use Base.RefValue instead of SomeValue)

But this and Array{T}-based solution are both dangerous, as they do not call the constructor. For example:

struct OrderedPair
    small::Int
    large::Int
    OrderedPair(x, y) = new(min(x, y), max(x, y))
end

isok(pair::OrderedPair) = pair.small <= pair.large

sum(!isok, Vector{OrderedPair}(undef, 100))  # != 0

It might be better to restructure your program to avoid this pattern.

I think that

gimme(::Type{T}) where T = (@assert isbitstype(T); Array{T}(undef)[])

should work.

Regarding the Array-solutions: Consider e.g.

julia> Ref{Core.CodeInfo}()[];
ERROR: UndefRefError: access to undefined reference

This will throw an error for non-bitstypes, and avoids the foreign function calls from Array. I.e. it is a no-op if you just need some value for dispatch.

Generally, consider

julia> macro new(T)
       return Expr(:new, T)
       end

usable by e.g.

julia> ci=@new Core.CodeInfo;

julia> typeof(ci)
Core.CodeInfo

julia> ci
CodeInfo(
signal (11): Segmentation fault

This will always succeed in obtaining an object of your type, bypassing inner constructors. It basically obtains an allocation, zeros pointer fields, and sets the object header (containing type-info and gc flags).

As you saw from from the example, this leads to nullpointer fields that JITed code doesn’t expect, hence segfault instead of exception. This only is an issue for non-isbits fields, and julia code that may access the contents. Your call whether this falls into the realm of “don’t care about the contents”. Garbage collector and runtime functions (stuff implemented in C, like objectid) will deal with these impossible null-objects just fine.

(you can also construct truly toxic objects that crash the garbage collector; I am assuming that you don’t want them)

PS. This only works for concrete types.

Deciding whether an abstract type is “strongly inhabited” (whether instances can be created without cheating) or “weakly inhabited” (whether concrete subtypes exist) or completely uninhabited is quite non-trivial! Don’t expect a simple solution, this is probably undecidable (some typetheory/PL persons chime in here).

PPS. Afaiu these uninitialized objects should not introduce crashes in code that doesn’t throw an undef-error already, because we don’t allow llvm to speculatively load the pointer (we don’t set dereferencable flags). No idea whether that will change that in the future. If you really care, then you should ask yuyichao.

1 Like