Destructuring syntax in julia 1.7

To me, (a = 1, b=2) is literal, (;a, b) or (; :a =>1 , :b => 2) is kinda non-literal. And a bit weird to have ; as prefix. This syntax is also not mathematical.
This syntax seems out of vacuum, not from mathematics.

structs are not from mathematics either. I don’t see the problem.

To me, the “non-literality” of (; a, b) is why this works. Just like in function arguments, where the semicolon signals “ordered arguments end here, from now on only specified, ‘extra’ information”, it means “this tuple is not a normal, ordered, tuple”.

7 Likes

The semicolon is used consistently to mark “here begin keywords” throughout the language and have since Julia 0.2 (IIRC), so it certainly doesn’t come out of nowhere.

11 Likes

It’s even required by YASGuide and BlueStyle.

YASGuide

In argument lists, always separate positional arguments from keyword arguments using a semicolon ( ; ).

BlueStyle

When calling a function always separate your keyword arguments from your positional arguments with a semicolon. This avoids mistakes in ambiguous cases (such as splatting a Dict ).

3 Likes

It doesn’t come out of nowhere for a seasoned Julia programmer, but I imagine it is fairly surprising for people coming from most other languages. Which is a pity, because IMHO Julia does very well on that front otherwise.

You don’t have to be that seasoned. Day three of reading the manual, tops.

That’s assuming you are in the privileged position where you can set aside three days just to read the manual of yet another programming language. My point was that if you know how to program in any language, then you probably can read most Julia code without referring to the manual at all. The (; foo) = bar syntax is a major exception to this rule, and it’s one which is also potentially quite hard to google.

1 Like

I’m sorry, but why should Julia satisfy such a ridiculous requirement? Do you really think there’s a language out there that does? Do you really think someone who’s only ever done Common Lisp would be able to read most Python code without a manual? Or that someone who only knows Python would never need a manual to read Java?
Julia is its own language, and is under no obligation to be readable without a manual by someone “who knows to program in another language”. As it is, Julia is very readable already, and moreover very consistent in its syntax, and you can’t realistically expect more of a programming language.

11 Likes

I agree on the difficulties that ; poses for beginners. But at the same time I think this:

is asking too much. A big part of what makes Julia appealing is its syntax being more expressive than say Matlab or Python. And you can hardly have both “more expressive syntax” and “knowing Matlab/Python is enough to read the code”…

I mean even basic array literals are un-understandable without reading the manual!

A = 1:3
B = [A A]
C = [A, 5:9]
D = [A; 5:9]

Maybe a Matlab/Python user thinks they understand this code, but they’re probably wrong. They’re also unlikely to guess what

:x

means unless they happen to know Ruby or another language with symbols.

Then there’s broadcasting:

x = 0:0.1:pi
A = cos.(x) .+ rand.()

Good luck understanding this without reading about loop fusion…

There’s also chained comparisons:

1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5

Or the convention-based difference between

filter(...)

# and

filter!(...)

and probably many more examples…

I’m personally happy Julia offers some pleasant, original (or at least less common) syntax rather than a rehash of 2-3 dominant languages :slight_smile:

11 Likes

Thanks for all the explanations. I can get the syntax design via take ; as separator not prefix.
While as separator it surely make sense.

2 Likes

Sorry, poor choice of words on my end. When I said “you should be able to read Julia without a manual”, I meant “you probably would be able to do that”. The point that I was trying to make is exactly the one you are raising, which is that Julia is very readable. Thus (;foo) = bar is a bit of an odd one out.

I agree with you that there are some features of Julia which you will not be able to make sense of without a manual, but for most of them it’s hard to think of a better way. Personally, I’m not convinced (;foo) = bar falls into this category. I’d argue the old-style @unpack foo = bar is potentially easier to grasp, and if not then at least there’s the obvious ?@unpack to get help.

Having said that, I of course understand that many people way smarter than myself must have thought very carefully about why (;foo) = bar is better than @unpack foo = bar, and I imagine I will come to agree with them sooner or later. However, I’m not there yet, and I assume others aren’t either.

2 Likes

This is analogous to user asking, “what is a[3]?”, and very few would think having getindex(a, 3) everywhere is a good idea.

julia> Meta.@lower (;re) = a
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ %1 = Base.getproperty(a, :re)
│        re = %1
└──      return a
))))

in general, ? doesn’t help with syntax question, but @lower does

1 Like

If beginners don’t know about this syntax, they’re not very likely to know about Meta.@lower either, or how to read it

well, but that’s like saying user don’t know how to use >?, it’s one-time and universal enough I won’t worry about it.

Is it really that much more surprising or ‘odd’ than slurp/splat syntax or destructuring of general iterables?

(For the record, I’m not a big fan of this syntax either, but not because you have to look it up in the manual.)

Could the help system be able to give nice help for something like a (;foo) = bar expression?

1 Like

It’s a slightly weird syntax, but it’s a useful feature and this is the natural syntax for it. How did we get here?

Methods definitions

  1. Positional args: f(x, y)
  2. Positional and keyword args with defaults: f(x, y; a=1, b=2)
  3. Positional and keyword args without defaults: f(x, y; a, b)
  4. No positional args with defaults: f(; a=1, b=2)
  5. No positional args without defaults: f(; a, b)

Tuple syntax

  1. Construction, like 1 without the function: (x, y)
  2. Destructuring, like 7 but left of an assignment: (x, y) = ...

Named tuple syntax

  1. Construction with explicit values, like 4 without the function: (; a=1, b=2)
  2. Construction with implicit values, like 5 without the function: (; a, b)
  3. Destructuring, like 10 but left of assignment: (; a, b) = ...

The only thing that’s new in Julia 1.7 is the last item—named tuple destructuring. Once you see it in the context of all these other syntaxes, perhaps it becomes clear why it’s the only syntax choice that fits in with all the rest.

31 Likes

Might I suggest a section of the manual devoted to the concept of destructuring and examples of these various syntaxes?

8 Likes

That’s a great idea and would be an excellent doc contribution if someone cares to take a crack at it.

1 Like