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
.
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)?
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
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.