On Wed, May 26, 2021 at 8:44 PM Steven D'Aprano
On Tue, May 25, 2021 at 10:10:12PM +1000, Chris Angelico wrote:
On Tue, May 25, 2021 at 5:29 PM Steven D'Aprano
wrote: Here's a counter-proposal: we have a special symbol which is transformed at compile-time to the left hand assignment target as a string. Let's say we make that special expression `@@` or the googly-eyes symbol.
[...]
Targets aren't limited to a single bare name.
spam.eggs = @@ # spam.eggs = 'spam.eggs'
mylist[2] = @@ # mylist[2] = 'mylist[2]'
What about:
mylist[ 2 ] = @@
? I'm inclined to say that the assignment target is reconstructed from the AST, in order to make it consistent (so this would also assign the string 'mylist[2]'). But, again, bikesheddable.
Let the implementation decide whether it is easier to get the target from the source code or the AST. I don't care either way.
Fair enough. This sort of thing would need to be settled before a PEP could be accepted, but by then, there'll want to be a reference implementation.
Chained assignments transform to a tuple of target names:
spam = eggs = cheese = func(arg, @@) # spam = eggs = cheese = func(arg, ('spam', 'eggs', 'cheese'))
Hmm. Everything else gives you a single string, this one doesn't. I'd actually be inclined to switch around this one and the next one...
A complication I just thought of is that you can have chained assignment within a sequence unpacking assignment:
spam, eggs, aardvark = foo = bar, hovercraft = 'abcd'
and the other way around:
spam = eggs = (aardvark, foo, bar) = hovercraft = 'abc'
That's going to make things tricky.
Very very good point. Ouch. It'd probably be safest to define it to always be a single string, and then have a fully-nestable and recursive system. So instead of simply separating with comma or equals or whatever, it might be best to group AND separate. spam, eggs = "@@" # "[spam,eggs]" spam = eggs = "@@" # "{spam,eggs}" (spam, eggs) = (foo, bar) = "@@" # "{[spam,eggs],[foo,bar]}"
Questions:
1) Is this restricted to the "=" assignment operator, or will other operators trigger this too? x += f(@@) # ? if x := f(@@): # ?
I hadn't thought that far ahead. I did think that we ought to exclude the walrus operator because it would be ambiguous:
spam = eggs * (cheese:=foo+bar(@@))
Does @@ get the value 'cheese' or 'spam'? If we require an assignment statement, then it can only be 'spam' and the ambiguity is gone.
Yeah, I'd agree about :=. Less clear about +=, but as with some of the others, it may be best to (a) leave it restricted with room for expansion, and/or (b) let a reference implementation guide the decision.
2) What about other forms of assignment? for spam in foo(@@): # ?
YAGNI.
Absolutely agree, especially because of this case: spam = [ord(x) for x in @@] If for loops on their own don't define an @@ target, then for loops inside comprehensions won't either, and this wouldn't be ambiguous.
3) Is this a string literal, or a magic token that happens to evaluate as a string?
An actual string.
Either way, it would be a string. The difference is that string literals can be placed adjacent to each other:
"{1}" f' - {1+2=} - ' '{2}' '{1} - 1+2=3 - {2}'
Which goes to show, btw, that an f-string is still a literal, even though it's not a constant.
x = @@ ".json" # Legal if @@ is a string literal
Heh, I wouldn't necessarily require that. (Nor would I object to it.) Implicit string concatenation is a nice feature, but I'm not sure we want to extend it. Its not hard to slot an explicit `+` in there.
True. Probably another thing best guided by the reference implementation. I think all these open questions are minor details, but the core proposal is strong enough to handle the uncertainty. Might be worth starting a dedicated thread for it. ChrisA