The following code does not work:
using StaticArrays, Parameters
import Base.zero
const SEGMENTS = 6
# struct, defining the physical parameters of one spring
@with_kw mutable struct Spring{I, S}
p1::I = 1 # number of the first point
p2::I = 2 # number of the second point
length::S = 1.0 # Current unstressed spring length
c_spring::S = 1.0 #
damping::S = 0.1 #
end
const SP = Spring{Int16, Float64}
function zero(::Type{SP})
s = SP()
s.p1 = 0
s.p2 = 0
s.length = 0.0
s.c_spring = 0.0
s.damping = 0.0
s
end
@with_kw mutable struct KPS4{S, P, SP}
masses::MVector{P, S} = ones(P)
springs::SVector{P-1, SP} = SVector{P-1, SP}(zeros(SP, P-1))
end
function KPS4()
KPS4{Float64, SEGMENTS+1, SP}()
end
kps = KPS4()
Error message:
julia> include("src/bug.jl")
ERROR: LoadError: MethodError: no method matching -(::TypeVar, ::Int64)
Closest candidates are:
-(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at ~/packages/julias/julia-1.7/share/julia/base/int.jl:86
-(::Base.TwicePrecision, ::Number) at ~/packages/julias/julia-1.7/share/julia/base/twiceprecision.jl:293
-(::LinearAlgebra.UniformScaling, ::Number) at ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/LinearAlgebra/src/uniformscaling.jl:147
...
Stacktrace:
[1] top-level scope
@ ~/.julia/packages/Parameters/MK0O4/src/Parameters.jl:611
[2] include(fname::String)
@ Base.MainInclude ./client.jl:451
[3] top-level scope
@ REPL[1]:1
in expression starting at /home/ufechner/repos/KiteModels/src/bug.jl:27
What am I doing wrong?
The following code works fine:
using StaticArrays, Parameters
import Base.zero
const SEGMENTS = 6
# struct, defining the phyical parameters of one spring
@with_kw mutable struct Spring{I, S}
p1::I = 1 # number of the first point
p2::I = 2 # number of the second point
length::S = 1.0 # Current unstressed spring length
c_spring::S = 1.0 #
damping::S = 0.1 #
end
const SP = Spring{Int16, Float64}
function zero(::Type{SP})
s = SP()
s.p1 = 0
s.p2 = 0
s.length = 0.0
s.c_spring = 0.0
s.damping = 0.0
s
end
springs = SVector{3, SP}(zeros(SP, 3))
Output:
julia> include("src/working.jl")
3-element SVector{3, SP} with indices SOneTo(3):
SP
p1: Int16 0
p2: Int16 0
length: Float64 0.0
c_spring: Float64 0.0
damping: Float64 0.0
SP
p1: Int16 0
p2: Int16 0
length: Float64 0.0
c_spring: Float64 0.0
damping: Float64 0.0
SP
p1: Int16 0
p2: Int16 0
length: Float64 0.0
c_spring: Float64 0.0
damping: Float64 0.0
But why can’t I use this array of structs as element of another struct?
ERROR: LoadError: MethodError: no method matching -(::TypeVar, ::Int64)
This comes from
@with_kw mutable struct KPS4{S, P, SP}
masses::MVector{P, S} = ones(P)
springs::SVector{P-1, SP} = SVector{P-1, SP}(zeros(SP, P-1))
end
Most specifically because of springs::SVector{P-1, SP} = ...
. You cannot do arithmetic with the type parameters of a parameterized struct
in the definition of its fields. Julia simply do not support it. If I am not wrong the ComputedFieldTypes package can be used to overcome this limitation (not sure if in all cases).
1 Like
Ok, this works:
using StaticArrays, Parameters
import Base.zero
const SEGMENTS = 6
# struct, defining the phyical parameters of one spring
@with_kw mutable struct Spring{I, S}
p1::I = 1 # number of the first point
p2::I = 2 # number of the second point
length::S = 1.0 # Current unstressed spring length
c_spring::S = 1.0 #
damping::S = 0.1 #
end
const SP = Spring{Int16, Float64}
function zero(::Type{SP})
s = SP()
s.p1 = 0
s.p2 = 0
s.length = 0.0
s.c_spring = 0.0
s.damping = 0.0
s
end
@with_kw mutable struct KPS4{S, P, Q}
masses::MVector{P, S} = ones(P)
springs::Vector{Q} = zeros(Q, P)
end
function KPS4()
KPS4{Float64, SEGMENTS+1, SP}()
end
kps = KPS4()
But I want to have an SVector of Springs, not a vector. Any idea how to achieve that?
This works:
using StaticArrays, Parameters
import Base.zero
const SEGMENTS = 6
# struct, defining the phyical parameters of one spring
@with_kw mutable struct Spring{I, S}
p1::I = 1 # number of the first point
p2::I = 2 # number of the second point
length::S = 1.0 # Current unstressed spring length
c_spring::S = 1.0 #
damping::S = 0.1 #
end
const SP = Spring{Int16, Float64}
function zero(::Type{SP})
s = SP()
s.p1 = 0
s.p2 = 0
s.length = 0.0
s.c_spring = 0.0
s.damping = 0.0
s
end
@with_kw mutable struct KPS4{S, P, Q, SP}
masses::MVector{P, S} = ones(P)
springs::SVector{Q, SP} = zeros(SP, Q)
end
function KPS4()
KPS4{Float64, SEGMENTS+1, SEGMENTS, SP}()
end
kps = KPS4()
Slightly inconvenient, but not much…
Thanks a lot!
1 Like
My pleasure. You did most of the work. I just gave a nudge in the right direction.