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[1]). 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[1], 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?
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 SArrays by creating an ordinary array and then converting it, like you tried. This should be avoided, always make sure to directly create an SArray.
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.