Group of variables to named tuple: built-in solution?

I regularly have the use case that I would like to convert a group of variable references to a named tuple with the reference names as keys and the referenced values as vals (usually to improve self-documentation of code when returning results from a function call):

X = 1, Y = (1,2), Z = 0.9
t = (X = X, Y = Y, Z = Z)

-> (X = 1, Y = (1, 2), Z = 0.9)

To practice metaprogramming, I came up with the following macro to do this:

macro nt(ex)
    Expr(:tuple, [Expr(:(=), esc(arg), arg) for arg in ex.args]...)
end

@nt X, Y, Z

-> (X = 1, Y = (1, 2), Z = 0.9)

However, in order to avoid copying this macro everywhere, is anyone aware of a built-in way in julia to do this?

I am not aware of a built-in solution, which is why I wrote

2 Likes

Thanks, looks like a nicely focused and lightweight dependency. I will definitely use that if no pure-Base solution is available.

Would be nice to see that functionality in Base!

If https://github.com/JuliaLang/julia/issues/29333 happens then it would be natural for (; X, Y, Z) to be shorthand for the named tuple (X=X, Y=Y, Z=Z).

1 Like

I had to stare a while at your question to understand what you were getting at.
Please let me know if the following example captures the essence of your scenario.

julia> stats(data) = mean(data), extrema(data), std(data)
stats (generic function with 1 method)

julia> stats(3:41)
(22.0, (3, 41), 11.40175425099138)

What do those numbers mean?

So you rewrite the function to make it more self documenting

julia> stats(data) = begin
          avg=mean(data)
          min_max=extrema(data)
          std_dev=std(data)
          return (avg=avg, min_max=min_max, std_dev=std_dev)
       end
stats (generic function with 1 method)

julia> stats(3:41)
(avg = 22.0, min_max = (3, 41), std_dev = 11.40175425099138)

But you don’t like the return statement (avg=avg, min_max=min_max, std_dev=std_dev)
Instead you’d prefer to write

return @nt avg, min_max, std_dev

or with Stefan’s syntax

return (; avg, min_max, std_dev)

Do I understand your scenario correctly?

1 Like

I’m not completely sure yet if I like the general proposal in that issue (variable names translating directly to keyword argument keys), but this syntax would indeed be concise for the named tuple construction case. While I’m not sure I would have guessed this syntax correctly, it may also become more intuitive after one is used to thinking in the “variable name translates directly to keyword” mindset proposed in the issue.

Yes, that is a nice summary of the use-case.

https://github.com/samoconnor/SymDict.jl has a macro for capturing local variables into a Dict (this is ~4 years old, so it was pre-named-tuples).

a = 1
b = 2
@SymDict(a,b)

Dict{Symbol,Any}(:a=>1,:b=>2)

(AWSCore.jl uses Dict{Symbol} to pass around various config parameters, options, request meta-data etc. I have been thinking recently that it might be better to use named tuples for this, or even just Vector{Pair{Symbol}})

1 Like