
On Wed, May 26, 2021 at 8:44 PM Steven D'Aprano steve@pearwood.info wrote:
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 steve@pearwood.info 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:
- 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.
- 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.
- 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