mauro3 / UnPack.jl

`@pack!` and `@unpack` macros
MIT License
86 stars 13 forks source link

Request - unpack with default values #17

Open Lincoln-Hannah opened 3 years ago

Lincoln-Hannah commented 3 years ago

Would it be possible to add a feature to allow unpacking with optional default values?

struct Foo
    a
    b
    c
end

p = Foo(10, 20,30)

@unpack { a=1, b,  x=1 }  =  p

a, b, x # gives (10, 20,  1)

@unpack { a=1, b, x }  =  p       #gives Error - x not present in p and no default value set.
mauro3 commented 3 years ago

I'm not sure. Shouldn't this be the duty of the type? Or, what does it mean to get a value from a type which doesn't have that value defined? For this you could just define a getproperty function.

goerz commented 3 years ago

I might like this as well, for unpacking keyword arguments:

julia> kwargs = Dict(:a => 1, :b=> 2)
Dict{Symbol, Int64} with 2 entries:
  :a => 1
  :b => 2

julia> @unpack a, b, c = kwargs
ERROR: KeyError: key :c not found

In the above example, I would like to have c as nothing.

The use case is that I have a solve(method; kwargs...) routine that delegates to different solve_method1(;kwargs...), solve_method2(;kwargs...), etc. The solve_method1 takes different keyword arguments than solve_method2, and I would like to call the top-level solve with combined kwargs for all the different methods. The sub-methods should then extract only those keyword arguments that they can handle, but also use defaults for any missing arguments.

I can do this manually with one get per keyword argument, of course, but it might be nice to do it concisely in one line with @unpack.

mauro3 commented 3 years ago

Doesn't that work already:

julia> solve(;s1 =1, kwargs...) = solve_m1(;s1=s1, kwargs...)
solve (generic function with 1 method)

julia> solve_m1(;s2=6, kwargs...) = @show kwargs
solve_m1 (generic function with 1 method)

julia> solve()
kwargs = Base.Iterators.Pairs(:s1 => 1)
pairs(::NamedTuple) with 1 entry:
  :s1 => 1

julia> solve(a=1)
kwargs = Base.Iterators.Pairs(:s1 => 1, :a => 1)
pairs(::NamedTuple) with 2 entries:
  :s1 => 1
  :a  => 1

(at least mostly)