Undefs.jl: Convenience and Experiment

Undefs.jl

I created a registered package called Undefs.jl that exports three names:

  1. undefs(A = Array, T = Float64, dims) = A{T}(undef, dims): a convenience method similar to ones, zeros, trues, and falses.
  2. undef!(array::Array, index=1): An experimental method to reset an element to an #undef state. This also works on Base.RefValue.
  3. @undef! A[1]: A macro to make the use of the undef! easier.

Demonstration of the convenience constructor, undefs

julia> using Undefs

julia> mutable struct Foo
           Foo(str) = finalizer(_->@async(println(str)), new())
       end

julia> undefs(5, 3)
5×3 Matrix{Float64}:
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> undefs(Foo, 5, 3)
5×3 Matrix{Foo}:
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef

julia> A = undefs(Array, Foo, 5, 3)
5×3 Matrix{Foo}:
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef

julia> using OffsetArrays

julia> undefs(OffsetArray, UInt8, 5, 3)
5×3 OffsetArray(::Matrix{UInt8}, 1:5, 1:3) with eltype UInt8 with indices 1:5×1:3:
 0xf0  0x7f  0x00
 0x76  0x00  0x00
 0xf1  0x00  0x00
 0x3a  0x00  0x00
 0x3f  0x00  0x00

Demonstration of @undef!

julia> A[1] = Foo("bye world")
Foo()

julia> A
5×3 Matrix{Foo}:
    Foo()  #undef  #undef
 #undef    #undef  #undef
 #undef    #undef  #undef
 #undef    #undef  #undef
 #undef    #undef  #undef

julia> @undef! A[1]

julia> A
5×3 Matrix{Foo}:
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef

julia> GC.gc()
bye world

Discussion

Undefs.jl is a meant as experimental convenience package and is not meant for production. The convenience constructor, undefs is meant to advance the conversation from recurring calls for a simpler way to allocate arrays without initialization. Additionally, the function undef! and the macro @undef! are highly experimental and use internal details of Julia’s array implementation to unassign elements from arrays of mutable structures.

While this package provides some convenient tools to play with, I encourage users to seek alternatives as described in the package README.

3 Likes

There’s a Base function for unsetting Array elements, if you don’t want to worry about the internal details yourself (which a prone to changing often). Undefing any other field by unsetting them is undefined behavior, and may lead to miscompilation or program crashes (pun intended)

1 Like

This package is not meant to be taken too seriously. What’s the name of the Base function?

Do you mean the exported C function jl_arrayunset ?

Yes, but I think there is also a faster version of that C function in Julia

Base._unsetindex! ?

Yes

1 Like

Is there a version intended for mutable structs or Base.RefValue?

No, the compiler relies on knowing it does not happen

1 Like

I see. So array elements can be unset, but not elements of mutable structs like Base.RefValue?

correct