Meaning and alternatives to "undef" when initializing vectors

It is not that I have problems using this, but particularly for didactic purposes I feel I need a clarification:

Whenever I initialize a vector of, lets say, integers, using, for example

x = Vector{Int64}(undef,3)

There seems to be no other option to be put in the place of undef. I understand what undef is, but the syntax seems to suggest that something else could be used there to initialize the vector with specific values.

Thus, I have two questions:

  1. In the initialization of numerical arrays (at least), that syntax accepts anything else in the place of undef? If so, what?
  2. If not, is there any profound reason to maintain the syntax with that redundancy? Could it be adapted to accept, for example, Vector{Int64}( index -> f(index), 3 ) to initialize a vector with a specific function of the indexes of the vector or anything else?

Just to clarify, I do not think that any of that would be needed. I am more concerned in understanding the reason behind that syntax, perhaps to explain to students.

Alternatively, wouldn’t be nice to have the possibility of initializing an array of undef values using something like

x = undef(Float64,3)

that would look consistent with the zeros(3) and ones(3) options.

1 Like

The only other option I know of in Base is I:

julia> Matrix{Float64}(I, 3, 3)
3×3 Array{Float64,2}:
 1.0  0.0  0.0
 0.0  1.0  0.0
 0.0  0.0  1.0

Edit: You need using LinearAlgebra to get I

2 Likes

Oh, looking at methods(Matrix{Float64}), it looks like you can use missing as an initializer:

julia> Matrix{Union{Float64, Missing}}(missing, 3, 3)
3×3 Array{Union{Missing, Float64},2}:
 missing  missing  missing
 missing  missing  missing
 missing  missing  missing

and likewise with nothing.

2 Likes

Yes, but in that case we have to add the Union{} stuff there. It is a very niche use, I think (I’ve never seen the use of that in numerical computing).

Didn’t know of that, and, in any case, it doesn’t work here :frowning:

julia> Matrix{Float64}(I, 3, 3)
ERROR: UndefVarError: I not defined

You need

using LinearAlgebra 

to import I.

2 Likes

And what kind of stuff is I? meaning, how to implement something else if we wanted to?

julia> typeof(I)
UniformScaling{Bool}

Try @edit Matrix{Float64}(I, 3, 3) and you’ll see that there’s nothing special about I in particular, except that someone has gone ahead and implemented:

## Matrix construction from UniformScaling
function Matrix{T}(s::UniformScaling, dims::Dims{2}) where {T}
    A = zeros(T, dims)
    v = T(s.λ)
    for i in diagind(dims...)
        @inbounds A[i] = v
    end
    return A
end
Matrix{T}(s::UniformScaling, m::Integer, n::Integer) where {T} = Matrix{T}(s, Dims((m, n)))

You can do exactly the same thing: define some struct MyCustomInitializer ... and then implement Matrix{T}(::MyCustomInitializer, ...) to do whatever behavior you want to provide.

6 Likes

I is a struct designed to behave like an identity matrix of whatever size is needed in context. You would implement it by making a strut that stores no data, and has correctly implemented routines for all the operations you wanted it to support.

1 Like

That clarifies a lot. Thank you.

But would it make sense to let

Array{Int, 2}(5, 3, 3)

behave like fill(5, 3, 3)? It just seems like undef and I and missing are special-cased, and I don’t understand why it doesn’t work for ‘everything’?

See issue:

4 Likes