Destructuring syntax in julia 1.7

1.7 introduced new language feature:
(; a, b) = x can now be used to destructure properties a and b of x . This syntax is equivalent to a = getproperty(x, :a); b = getproperty(x, :b)

From a reader perspective(much more compare to writer perspective in action), I can not appreciate the elegance of this syntax. It’s too not “mathematical”.
Existing argument destructuring for tuple is much elegant as there is an isomorphism between the delcare structure and the data structure.
Why this new syntax don’t have this feature?

2 Likes

It does, (; a, b) creates a NamedTuple just as (a, b) creates a Tuple. Note however that just as regular destructuring doesn’t just work with tuples but with any iterable, property destructuring also works with any objects that have fields.

16 Likes

A surprise, I didn’t know (; a = 1, b =2) can create a named tuple. :grinning:
I read out the manual, not found this. It’s not mentioned in manual right?

1 Like

It is mentioned in the docstring at least: Essentials · The Julia Language

TIL, thanks. Does this mean UnPack.jl isn’t necessary anymore? This seems equivalent

I see, thanks

Personally, I feel a bit uncomfortable that the names on the left hand side influence which values are read on the right hand side.

But that’s the point isn’t it? So you can write

(; height, weight) = df

to extract two columns, and you don’t have to know/care about other columns or the order of these two columns in df.

@xfcjscn note that the “isomorphism” goes further as the syntax can also be used with existing variables:

a = 1
b = 2

nt = (; a, b)
5 Likes

Of course it’s the point, but it feels ‘magical’, like a macro, or ‘spooky action at a distance’.

Shouldn’t the specification of which fields to read be on the RHS, not the LHS?

I feel similarly about the kwarg thing, where

foo(;kw) 

is the same as

foo(;kw=kw) 
3 Likes

Ah I see your point. But I wouldn’t say it’s like macros: there are arbitrary syntax rules. This follows the rules, while macros allow you to bend the rules.

I think it’s a matter of habit. Probably if we had spent years writing NamedTuple([:a=>1, :b=>2]) we would think (a=1, b=2) is magical, but it’s just new syntax. For me it’s now quite natural to write plot(x, y; linewidth).

1 Like

It follows the syntax rules because the rules were changed :wink: The reason I bring up macros is that it looks like this ought to have a macro in front of it, like @destructure (;a, b) = x or @splat foo(;kw)

What I don’t like about it is that the name choices you make for variables enable special syntax. The syntax wouldn’t work if I wanted to destructure fields :a and :b into variables x and y. Similarly with kwargs.

(BTW, it’s not a big deal, really, but this thread made me come out with it now.)

4 Likes

That would require specifying the source and target names. The main motivation I think was precisely to avoid this repetition when you want to keep the same names.

Having the field specification on the “name binding” side is actually what makes the syntax so useful. Consider these cases:

for (; x, y) in eachrow(df)
    println("x-y = $(x-y)")
end

map(eachrow(df)) do (; x, y)
    x-y
end

I don’t know how that would work if the syntax was on the “RHS” (meaning eachrow(df) here).

Also I’m not sure you could implement this with a macro. I think it’s really the kind of thing where you need syntax.

3 Likes

I understand the purpose and the advantage, and I have no alternative suggestion to make it work otherwise. It just feels ‘magical’, and I don’t like it, and I wish it wouldn’t work at all, no matter how useful and practical it is.

I don’t dislike it very strongly, but I’m not a fan.

The obvious extension to this syntax is (; foo = a, bar = b) = x, of course :stuck_out_tongue:

1 Like

Is this already working for dataframes?

Yes there’s nothing special that DataFrames.jl needs to do: in general (; a, b) = x will do a = x.a and b = x.b. You can write e.g. a = df.a so it works.

2 Likes

Really cool.
NB: got confused because the command prints the whole dataframe but the variables are well assigned indeed.

This is what the @unpack macro from parameters does and looks like. I use it, but I agree in general with you, one has to be careful to keep the code understandable using that syntax. (I like that @unpack is more verbose, I would like to see that merged into base, but I’m not sure if it can be used everywhere where the new destructuring syntax is used, I guess it does not).

1 Like

Ah, suddenly I am almost reconciled with the (; a, b) way of creating tuples!