# StaticArrays field values printed as undef?

I’m using a StaticArrays.jl `FieldVector` for a 3-vector that can be both accessed by field name (`v.x`) as well as by index (`v`). I also added a `length` function to get the vector length:

``````using StaticArrays
using LinearAlgebra

struct vec3 <: FieldVector{3, Float32}
x::Float32
y::Float32
z::Float32

vec3() = zeros(Float32, 3)
vec3(x, y, z) = new(x, y, z)
end

import Base.length
length(v::vec3) = sqrt(dot(v,v))

v = vec3(0.5f0, 0.0f0, 0.5f0)

println(v)
println(v, v.x)
println(length(v))
``````

The `import Base.length` seems to screw up the printing of `v`, as I get the following output:

``````Float32[#undef, #undef, #undef]
0.50.5
0.70710677
``````

The first line suggests the vector fields have an undefined value, but the other two lines show the values are actually correct, they’re merely printed incorrectly. Removing the `import Base.length` line fixes this and produces:

``````Float32[0.5, 0.0, 0.5]
0.50.5
0.70710677
``````

Is this an expected side-effect of the import, or a bug?

`Base.length` should always return the number of elements in an array, breaking this assumption for your own `AbstractArray` type is expected to cause problems. It looks like you just want `norm` from `LinearAlgebra` here?

1 Like

I don’t think this is what you want:

``````jl> vec3()
3-element Vector{Float32}:
0.0
0.0
0.0
``````

I think you should use

``````vec3() = new(0f0, 0f0, 0f0)
# or
vec3() = vec3(0f0, 0f0, 0f0)
``````

Ah, didn’t realize `vec3` ends up being an `AbstractArray`, but that makes sense of course.

``````julia> supertypes(vec3)
(vec3, FieldVector{3,Float32}, FieldArray{Tuple{3},Float32,1}, StaticArray{Tuple{3},Float32,1}, AbstractArray{Float32,1}, Any)
``````

I indeed noticed `norm` was working anyway as an alternative, but was wondering what was going on here.

So even though I declared `vec3()` as an inner constructor it can still return any type at all? Ugh.

Thanks to both of you!

Well, you explicitly specified that it should be `zeros(Float32, 3)`, and without passing it through `new`, so the compiler doesn’t have much choice. Maybe there could be a warning or something.

I think the special thing with inner constructors is that they have access to `new`, but if you don’t use it, that doesn’t matter. In fact, I don’t think `vec3` should be an inner constructor, it should be outer, and just call `vec3(0f0,0f0,0f0)`.

Right, not forgetting to use `new()` is crucial . But it’s also a bit surprising that a constructor that is defined within a struct can construct something that is of a different type unrelated to the struct.

One extra thing, though: even if the constructor automatically converted to the correct type, it would still have to go through an ordinary `Array` first, which would be very inefficient.

Sometimes I’ve seen people construct `SArray`s by creating an ordinary array and then converting it, like you tried. This should be avoided, always make sure to directly create an `SArray`.

1 Like

Maybe a construction like this is more interesting:

``````julia> struct vec3{T} <: FieldVector{3,T}
x::T
y::T
z::T
end

julia> zero(vec3{Float32})
3-element vec3{Float32} with indices SOneTo(3):
0.0
0.0
0.0

``````

Or, if you know that you will never use anything else than `Float32`, just

``````julia> struct vec3 <: FieldVector{3,Float32}
x::Float32
y::Float32
z::Float32
end

julia> zero(vec3)
3-element vec3 with indices SOneTo(3):
0.0
0.0
0.0

``````

Note that that type of structure allows you to write generic functions, like this:

``````julia> function f(x::Vector{T}) where T
y = zero(T)
for v in x
y += v
end
y
end
f (generic function with 1 method)

julia> x = [ rand(vec3{Float32}) for i in 1:3 ];

julia> f(x)
3-element vec3{Float32} with indices SOneTo(3):
0.16435432
1.3771235
1.274611

julia> x = [ 1, 2, 3 ];

julia> f(x)
6

``````

Thus if you decide to use `vec2` or `vec4` you don’t need to rewrite any of the functions.