Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

default values for destructuring syntax: (; x=default) = y #51940

Open
stevengj opened this issue Oct 30, 2023 · 8 comments
Open

default values for destructuring syntax: (; x=default) = y #51940

stevengj opened this issue Oct 30, 2023 · 8 comments
Labels
parser Language parsing and surface syntax speculative Whether the change will be implemented is speculative

Comments

@stevengj
Copy link
Member

stevengj commented Oct 30, 2023

As commented by @simeonschaub in #39285, it might be nice to have a way to provide default values in destructuring syntax. This came up recently on discourse.

A natural syntax for this might be:

(; a=default_a, b, c=default_c) = x

where the default values are employed if !hasproperty(x, :a) and/or !hasproperty(x, :c).

More precisely, I think it would be good to specify that the default-value expressions are only evaluated if the corresponding property on the rhs does not exist. So that you could do (; a=default_a()) = x and default_a() would only be called if x.a does not exist, functionally equivalent to a = hasproperty(x, :a) ? x.a : default_a().

@stevengj stevengj added speculative Whether the change will be implemented is speculative parser Language parsing and surface syntax labels Oct 30, 2023
@simeonschaub
Copy link
Member

I guess the issue here is that if we think of this syntax more in terms of pattern matching, one might expect this to instead unpack x.a into default_a and x.c into default_c. So we probably want to think carefully about which behavior is more useful and what feels most intuitive with the rest of the language

@stevengj
Copy link
Member Author

stevengj commented Oct 30, 2023

To me, in the context of Julia syntax it looks more like keyword arguments with default values, though of course this is a matter of taste. Moreover, it seems pretty useful since a = hasproperty(x, :a) ? x.a : default_a() is quite verbose, especially if you have many properties to unpack.

If you want to do renaming, it would seem more natural to mirror the using syntax and do something like(; a as renamed_a) = x, but of course you can already do renamed_a = x.a which is pretty clear and concise (no redundant symbols).

@simeonschaub
Copy link
Member

simeonschaub commented Oct 30, 2023

One thing I like about the pattern matching approach is that it makes property destructuring nestable which it's currently not. I often find myself wanting to express something like (; head, args=(_, a, b)) = :(1 + 2) to recursively destructure a property, especially in function arguments.

There currently isn't really a way to neatly express this in one line, so I do think composability is one argument in favor of this approach over your proposal. Using the as syntax for this instead is an interesting idea though

@stevengj
Copy link
Member Author

stevengj commented Oct 30, 2023

I often find myself wanting to express something like (; head, args=(_, a, b)) = :(1 + 2)

Recursive destructuring could instead use

(; head, (_, a, b) = args) = :(1 + 2) 

which looks more natural to me, and is disambiguated from default values by the tuple on the lhs of the =. Indeed, you could imagine combining it with default args:

(; head, (_, a=nothing, b=nothing) = args) = some_expr

@simeonschaub
Copy link
Member

which looks more natural to me, and is disambiguated from default values by the tuple on the lhs of the =.

It is disambiguous but I feel like this violates our unwritten syntax rules in terms of referential transparency. The rhs of the = in a destructuring expression should either always be a property name or always be an rvalue, but not change meaning based on whether the lhs is a symbol or tuple expression.

@stevengj
Copy link
Member Author

It is even weirder to have the rhs be the symbol you are assigning to, as in your suggestion.

@Pangoraw
Copy link
Contributor

What about using another assignment operator for the default value ?

(; a = new_name := default_value()) = some_expr
(; a := default_value()) = some_expr
(; a = new_name) = some_expr

@BeastyBlacksmith
Copy link

BeastyBlacksmith commented Feb 8, 2024

I guess the issue here is that if we think of this syntax more in terms of pattern matching, one might expect this to instead unpack x.a into default_a and x.c into default_c. So we probably want to think carefully about which behavior is more useful and what feels most intuitive with the rest of the language

To me this reads more like unpacking x.default_a into a, i.e. renaming while destructing, which would also be a nice feature to have.

Edit: I recognize that was already said ^^;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
parser Language parsing and surface syntax speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

4 participants