Can the @unpack_STRUCT macro in Parameters.jl be type stable?

I want to use the @unpack_STRUCT macro in Parameters.jl to unpack all fields of a mutable struct, but I need it to be type stable. Here is an example:

using Parameters, BenchmarkTools

@with_kw mutable struct S @deftype Float64
    a;b;c;d
end

function f!(s::S)
    @unpack a,b,c = s
    d = a*b*c
    @pack s = d
    return s
end

function g!(s::S)
    @unpack_S s
    d = a*b*c
    @pack_S s
end

In this example, f!(s) is type stable but g!(s) is not.

julia> s = S(2,3,4,1); @btime f!(s);
  16.682 ns (0 allocations: 0 bytes)

julia> s = S(2,3,4,1); @btime g!(s);
  4.641 μs (54 allocations: 3.13 KiB)

julia> @code_warntype g!(s)
Variables:
  #self# <optimized out>
  s@_2::S
  a::Float64
  b::Float64
  c::Float64
  d::Float64
  s@_7::Any

Body:
  begin
      s@_7::Any = s@_2::S
      a::Float64 = (Core.getfield)(s@_7::S, :a)::Float64
      b::Float64 = (Core.getfield)(s@_7::S, :b)::Float64
      c::Float64 = (Core.getfield)(s@_7::S, :c)::Float64
      d::Float64 = (Core.getfield)(s@_7::S, :d)::Float64 # line 15:
      d::Float64 = (Base.mul_float)((Base.mul_float)(a::Float64, b::Float64)::Float64, c::Float64)::Float64 # line 16:
      SSAValue(0) = $(Expr(:invoke, MethodInstance for (::Parameters.#kw##reconstruct)(::Array{Any,1}, ::Parameters.#reconstruct, ::S), :($(QuoteNode(Parameters.#reconstruct))), :($(Expr(:invoke, MethodInstance for vector_any(::Any, ::Vararg{Any,N} where N), :(Base.vector_any), :(:a), :(a), :(:b), :(b), :(:c), :(c), :(:d), :(d)))), :($(QuoteNode(Parameters.reconstruct))), :(s@_7::S)))
      s@_7::Any = SSAValue(0)
      return SSAValue(0)
  end::Any

Is there a way to make g!(s) type stable or do I need to list individual fields as I did in f!(s)?

It’s the @pack_S which is not type stable. I’ll look into it.

Yeah, I goofed on the title there. Thanks, I’ll follow any progress in the repo!

It’s fixed on the latest master.

2 Likes