Why does arrayref throw?

Wow, thanks for this very detailed post! Lots to unpack and to digest! (for a future day with more time)

I have a few direct reactions:

I like how the example illustrates that code written for, e.g. some numerical computation, should work well with both value types and reference types. I had not really though about this.

I fully agree that a default instance/value is a bad idea.

You compare the cost of initialization when going from “no initialization” to “initialization”, of course this can look bad (yes, I know “no initialization” requires “null initialization”, but still). Luckily, I think, initialization is usually not the dominant cost in a computation - and if it is, then that’s a pretty good sign you are using a dense structure when you should be using a sparse.

The Pascal example connects back to earlier discussion in this thread about incremental construction and sizehint!

function pascal(::Type{T}, n::Integer) where {T<:Real}
    A = T[]
    sizehint!(A, n*n)

    idx(i, j) = n * (j - 1) + i

    for j = 1:n
        for i = 1:n
            if i == 1 || j == 1
                push!(A, one(T))
            else
                push!(A, A[idx(i-1, j)] + A[idx(i, j-1)])
            end
        end
    end

    return reshape(A, (n,n))
end

Yes, your index-style implementation looks much better than this one.