Is there a Julia function similar to the R function `with`?

Hello,

In R, when you have a list like mylist <- list(a = 2, b = 3), then instead of doing mylist$a + mylist$b you can do with(mylist, a + b). Is there something similar in Julia for a named tuple like (a = 2, b = 3)?

Can you clarify what exactly you are trying to do? We have similar syntax with tables, but maybe you don’t even need the syntax and there is a better way to achieve your goal with idiomatic Julia.

Not exactly what you ask for, but you have the let-statement where you can do a small destructure

julia> mytup = (a=3, b=4)
(a = 3, b = 4)

julia> let (; a, b) = mytup
       a + b
       end
7
1 Like

@juliohm I have a large tuple params = (a = 1, b = 2, ..., j = 10) and a function with arguments a, b, …, j, I don’t want to type f(params.a, params.b, ..., params.j).

Hmm… but I just found a solution for this situation: f(params...) works.

But well, what if params is not ordered as the arguments of the function?

This has been discussed before, for example here and here.

My impulse is to accomplish something like this with function keywords, e.g.

julia> t = (a=2, b=3)
(a = 2, b = 3)

julia> foo(;a, b) = a + b
foo (generic function with 1 method)

julia> foo(;t...)
5
2 Likes

If you don’t need different methods for f you could define it with keyword arguments and call it by splatting those, i.e., f(; params...) as also suggested by @brendaisy.
In general, to replicate the functionality of R requires non-standard evaluation and could be done with a macro in Julia. The package StatsPlots has a similar macro for tables which allows you to write: @df mytable :a + :b. You could check their implementation and build something similar for named tuples. Yet, given the short syntax for unpacking names tuples as shown by @albheim a macro might not be necessary here.

For fun.

julia> macro with(container, expressions...)
           esc(:( let (; $(propertynames(getfield(__module__, container))...))=$container
               $(expressions...)
           end ))
       end
@with (macro with 1 method)

julia> let t=(a=2, b=3)
           @with t a+b
       end
5

julia> tup = NamedTuple(Symbol(c)=>c for c ∈ 'a':'j')
(a = 'a', b = 'b', c = 'c', d = 'd', e = 'e', f = 'f', g = 'g', h = 'h', i = 'i', j = 'j')

julia> @with tup (j, i, h, g, f, e, d, c, b, a)
('j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a')

julia> tup = (a=1, b=2, c=3)
(a = 1, b = 2, c = 3)

julia> @with tup begin
           local temp=a+b
           temp+c
       end
6

You can compare this against this macro. But you should also consider whether such a thing is even worthwhile, considering this.

Edit:

Oops, I polluted my global namespace. The above code does not, infact, work for locally-declared named tuples; it only works for globally-visible objects.

Looks like this works though. It’s quite clever.

3 Likes