Add a property to a StructArray

Is it possible to add a property to a StructArray?

The following code fails:

julia> using KiteUtils, StructArrays
julia> syslog=demo_syslog(7)

julia> function Base.getproperty(st::StructArray{SysState}, sym::Symbol)
           if sym == :x
               last.getfield(st, :X)
           elseif sym == :y
               last.getfield(st, :Y)
           elseif sym == :z
               last.getfield(st, :Z) # last.(st.Z)
           else
               getfield(st, sym)
           end
       end

julia> syslog.z
ERROR: type NamedTuple has no field z
Stacktrace:
 [1] component
   @ ~/.julia/packages/StructArrays/MdA9B/src/structarray.jl:307 [inlined]
 [2] getproperty(s::StructArrays.StructVector{SysState{7}, NamedTuple{(:time, :orient, :elevation, :azimuth, :l_tether, :v_reelout, :force, :depower, :v_app, :X, :Y, :Z), Tuple{Vector{Float64}, Vector{StaticArrays.MVector{4, Float32}}, Vector{Float64}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{StaticArrays.MVector{7, Float32}}, Vector{StaticArrays.MVector{7, Float32}}, Vector{StaticArrays.MVector{7, Float32}}}}, Int64}, key::Symbol)
   @ StructArrays ~/.julia/packages/StructArrays/MdA9B/src/structarray.jl:309
 [3] top-level scope
   @ REPL[6]:1

Additional info:

julia> typeof(syslog)
StructVector{SysState{7}, NamedTuple{(:time, :orient, :elevation, :azimuth, :l_tether, :v_reelout, :force, :depower, :v_app, :X, :Y, :Z), Tuple{Vector{Float64}, Vector{MVector{4, Float32}}, Vector{Float64}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{MVector{7, Float32}}, Vector{MVector{7, Float32}}, Vector{MVector{7, Float32}}}}, Int64} (alias for StructArrays.StructArray{SysState{7}, 1, NamedTuple{(:time, :orient, :elevation, :azimuth, :l_tether, :v_reelout, :force, :depower, :v_app, :X, :Y, :Z), Tuple{Array{Float64, 1}, Array{StaticArrays.MArray{Tuple{4}, Float32, 1, 4}, 1}, Array{Float64, 1}, Array{Float32, 1}, Array{Float32, 1}, Array{Float32, 1}, Array{Float32, 1}, Array{Float32, 1}, Array{Float32, 1}, Array{StaticArrays.MArray{Tuple{7}, Float32, 1, 7}, 1}, Array{StaticArrays.MArray{Tuple{7}, Float32, 1, 7}, 1}, Array{StaticArrays.MArray{Tuple{7}, Float32, 1, 7}, 1}}}, Int64})

Any idea?

Can you elaborate a bit, especially on last in your code?

What is it that you want as an output of syslog.z ?
Same as syslog.Z (upperase Z!) without redefining Base.getproperty ?

And what do you mean with last.getfield(st, :Z) # last.(st.Z) ?
What is the output of last.(st.Z) without redefining Base.getproperty ?

I tried your code but get

julia> syslog=demo_syslog(7)
ERROR: SystemError: opening file "data\\system.yaml": No such file or directory

If you want try yourself, here a more complete explanation how to reproduce the issue:

mkdir tmp
cd tmp
julia --project="."
using Pkg
pkg"add KiteUtils"
pkg"add StructArrays"
using KiteUtils, StructArrays
copy_settings()
log = demo_syslog(7)

function Base.getproperty(st::StructArray{SysState}, sym::Symbol)
           if sym == :x
               last.getfield(st, :X)
           elseif sym == :y
               last.getfield(st, :Y)
           elseif sym == :z
               last.getfield(st, :Z) # last.(st.Z)
           else
               getfield(st, sym)
           end
       end

julia> log.z
ERROR: type NamedTuple has no field z
Stacktrace:
 [1] component
   @ ~/.julia/packages/StructArrays/rICDm/src/structarray.jl:307 [inlined]
 [2] getproperty(s::StructVector{SysState{7}, NamedTuple{(:time, :orient, :elevation, :azimuth, :l_tether, :v_reelout, :force, :depower, :steering, :heading, :course, :v_app, :vel_kite, :X, :Y, :Z), Tuple{Vector{Float64}, Vector{StaticArrays.MVector{4, Float32}}, Vector{Float64}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{Float32}, Vector{StaticArrays.MVector{3, Float32}}, Vector{StaticArrays.MVector{7, Float32}}, Vector{StaticArrays.MVector{7, Float32}}, Vector{StaticArrays.MVector{7, Float32}}}}, Int64}, key::Symbol)
   @ StructArrays ~/.julia/packages/StructArrays/rICDm/src/structarray.jl:309
 [3] top-level scope
   @ REPL[17]:1

julia> log.Z
201-element Vector{StaticArrays.MVector{7, Float32}}:
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
 [0.0, 0.0007690057, 0.0030974336, 0.007050112, 0.012737092, 0.02031671, 0.030000001]
 [0.0, 0.0015380114, 0.006194867, 0.014100224, 0.025474183, 0.04063342, 0.060000002]
 [0.0, 0.002307017, 0.009292301, 0.021150336, 0.038211275, 0.060950134, 0.09]
 [0.0, 0.0030760227, 0.012389734, 0.028200448, 0.050948367, 0.08126684, 0.120000005]
 [0.0, 0.0038450283, 0.015487167, 0.03525056, 0.06368546, 0.101583555, 0.15]
 [0.0, 0.004614034, 0.018584602, 0.04230067, 0.07642255, 0.12190027, 0.18]
 [0.0, 0.00538304, 0.021682035, 0.049350783, 0.089159645, 0.14221698, 0.21000001]
 [0.0, 0.0061520454, 0.024779469, 0.056400895, 0.10189673, 0.16253369, 0.24000001]
 [0.0, 0.006921051, 0.0278769, 0.06345101, 0.11463383, 0.18285039, 0.27]
 ⋮
 [0.0, 0.1476491, 0.59470725, 1.3536215, 2.4455216, 3.9008086, 5.76]
 [0.0, 0.1484181, 0.59780467, 1.3606716, 2.4582586, 3.9211252, 5.7900004]
 [0.0, 0.1491871, 0.6009021, 1.3677217, 2.470996, 3.941442, 5.82]
 [0.0, 0.1499561, 0.60399956, 1.3747718, 2.483733, 3.9617586, 5.8500004]
 [0.0, 0.15072511, 0.60709697, 1.3818219, 2.49647, 3.9820752, 5.8800006]
 [0.0, 0.15149412, 0.6101944, 1.388872, 2.509207, 4.002392, 5.9100003]
 [0.0, 0.15226312, 0.6132918, 1.3959222, 2.521944, 4.022709, 5.9400005]
 [0.0, 0.15303212, 0.6163893, 1.4029722, 2.5346813, 4.0430255, 5.9700003]
 [0.0, 0.15380114, 0.6194867, 1.4100224, 2.5474184, 4.063342, 6.0000005]

log.Z is a vector of vectors, and I want to get the last elements of each of these vectors when I type
log.z .

Ok, what missed from the example before was just the

copy_settings()

This does what you want (only for :z):

function StructArrays.component(s::StructArray, key)
    if key == :z
		return last.(getfield(StructArrays.components(s), :Z))
	end
	getfield(StructArrays.components(s), key)
end

But, if this is a good idea or good style I doubt.
E.g. what if another StructArray has some field z?

This actually also works, I was not aware of this possibility:

julia> last.(log.Z)
201-element Vector{Float32}:
 0.0
 0.030000001
 0.060000002
 0.09
 0.120000005
 0.15
 0.18
 0.21000001
 0.24000001
 0.27
 ⋮
 5.76
 5.7900004
 5.82
 5.8500004
 5.8800006
 5.9100003
 5.9400005
 5.9700003
 6.0000005

Is there the possibility to assign a new type name to special struct arrays?

Like as an alias? I don’t know of such a possibility in general.

Edited above funtion as I missed the broadcasted last.

Like as an alias? I don’t know of such a possibility in general.

I mean, it would be nice if StructArrays of different Structs could have different types…