Page 1 of 2

MultiArg assignment

PostPosted: Wed Oct 08, 2008 8:34 pm
by hopscc
Opened a ticket for this but not a discussion (ticket:38)

1. Support multiple arg assignment ( tuple unpacking) - assignment to multiple args from a list-like-thing in a single statement
as in
Code: Select all
<multi arg commaSep list> = <List expression>

a,b = 1,2     #possible syntax
 a,b = fnReturns2Args()  #call to a method returning a list
 
x,y = [1,2]
# above approx equiv to
t = [1,2]
x=t[0]
y=t[1]
 

list=...something generating a list/array/string...
i,j,k = list # gets first 3 elements of list


2. Also support multiple assignment of Key and value pairs in a for statement
Code: Select all
for key, value in dict
...


3. Support multiple assignment from an IEnumeration expression in a for statement
Code: Select all
 for x,y in ..whatever_list_array_string
     ... do something with x and y

Re: MultiArg assignment

PostPosted: Wed Oct 08, 2008 8:54 pm
by hopscc
Item 1. is implemented.
With that 2. can be done manually relatively simply
Code: Select all
for kv in dict
    key, value = [kv.key, kv.value]
    ... rest of block...


Pythons implementation throws exception if arglist ( the x,y,z lhs variable name stream) length is not exactly same length as items in rhs expression.
My implementation does not; for shorter arglist the given args are assigned to from the start of the rhs list, longer arglist leaves additional lvalue args unchanged
from prior to the assignment expression
Code: Select all
a,b=[1,2,3]
assert a==1
assert b==2
# remaining rhs items ignored

c=9999
a,b,c = [1,2]
assert a==1
assert b==2
assert c == 9999   # c unchanged from prior to multi-arg assign


I think this silent do-what-I-mean behaviour is the most useful but I'd welcome any comments on this
( I actually think pref behaviour for the last case would be for c to be reset to its types default init value(nil, 0, '')
but theres some insurmountable opportunities I couldnt get round to implement that).

Re: MultiArg assignment

PostPosted: Wed Oct 08, 2008 9:06 pm
by hopscc
What is desired behaviour for 3. ?
I'd thought that it should obviously be
Code: Select all
for x,y in [1,2,3,4]
# iter1: [x,y] == [1,2]
# iter2: [x,y] == [3,4] .

But pythons implementation throws on this, demanding that the list be packaged as a list of 2-tuples ( in this case)
Code: Select all
# python
for x,y in [1,2],[3,4]]
#  iter1: [x,y] == [1,2]
# iter2: [x,y] == [3,4]


Which is most preferred/useful/desirable behaviour ?

What should happen here if num items in IEnumeration expression is not a multiple of number of assign-to args ??

Re: MultiArg assignment

PostPosted: Wed Oct 08, 2008 11:23 pm
by Charles
As I mentioned in direct email with you, I totally support this. It's only missing from Cobra because no one hasn't gotten around to it until now.

Regarding your questions:

-- The right hand values should number exactly the same as the left hand targets. A mismatch in count could easily indicate an error. And with slicing, the programmer can easily drop the extra values ("x, y = t[:2]").

-- In "for x, y ..." the enumerable target of the "for" should contain sequences or enumerables matching in length, just like Python.

-- Do you have type inference working?
a, b = 'foo', 3  # a is a String, b is an int


Two things that should work beyond Python are simple consequences of being on .NET:

-- The right hand values of a multi-target assignment could be a DictionaryEntry (found in System.Collections) or a KeyValuePair<of U, T> (found in System.Collections.Generic).

-- I think we could swing it so that the right hand values came from "out" parameters:
success, value = int.tryParse(s)

# currently, calling .tryParse is rather awkward, though no worse than C#:
value as int
success = int.tryParse(s, out value)


Those last two ideas are not necessary for the first patch to be applied. We can do things in stages. But matching the Python semantics is required; I think they were well thought out and fit in with Cobra.

Re: MultiArg assignment

PostPosted: Thu Oct 09, 2008 4:48 am
by hopscc
Yep, remember(and found ) the mail - thats what got me to do something about this...
Which also reminds me provided syntax for simplest multiarg case is
Code: Select all
a,b,c = [1,2,3]   # rhs literal list

The patch on the ticket has a comment re what to do (uncomment and comment some code) if want exception generated for mismatch (greater) lhs args length
I'd agree that that case is possibly more likely to be an error.

For the case of a shorter arglist I'm not convinced of the utility of forcing the programmer to explicitly have to truncate the list when its unnecessary to get/provide the assignment values.
- easy to do or not its still an extra (nitpicking) step
If its a programmer error (missing arg in lhs variable name list) then a shorter set of assigned items is gonna be obvious from the missing variable later....
depends on whether you think programmer should do additional bookkeeping for being explicit to system or system should assume programmer knows what they're doing and do
with what it has


OK re 'for' and matching length of sequence objects...

Type inference works as well as assignmentExprs ( since it basically just rewrites the multi arg assignment to a stream of single assignments)

Not looked at auto unpacking KeyValuePair (it'll fall out of multiargs in 'for' on a Dict I expect )- step 2), have to look at Dictionary Entry.

Are you talking of autodetecting and rewriting the return types for (library) methods returning 'out' values or explicitly wrapping some selected candidates??
...

Re: MultiArg assignment

PostPosted: Fri Oct 10, 2008 4:40 am
by Charles
Btw this works in Python for swapping values:
a, b = b, a
So the compiler can't always do a naive series of assignments.

Regarding the "out" params, I was thinking it would be pure syntactic sugar with no wrapper methods. But I haven't thought hard about the implementation or the fact that assignment can itself be an expression.

Regarding number arg lhs targets, I still insist that it be the correct number like in Python. If it's obviously the wrong number at compile-time that would be an error. If it happens at run-time, an exception.

Re: MultiArg assignment

PostPosted: Sat Oct 11, 2008 9:23 pm
by hopscc
This does the same in the current patch
Code: Select all
a,b = [b,a]

(Should have actually provided that example in one of the tests since its so common an example )


The 'out' parameter rewrite thing can be a subsequent enhancement when and if.

number lhs arg targets - and the reason(s) for this insistence would be?

Re: MultiArg assignment

PostPosted: Sun Oct 12, 2008 9:08 am
by Charles
-- Are you saying that "a, b = b, a" does swap the values? Or that you can only get the swap if you wrap the right hand side in a list?

-- I agree the "out" arg enhancement can be done later.

-- The insistence on the lhs count matching the rhs count is two fold:

One, it's in line with other aspects of Cobra, like if you say list[i] where i is out of range, the language doesn't give you nil or the last element. It gives you an error. Likewise if you say obj.foo where foo is undefined, you get an error. If you say x + y where x is 5 and y is "10", you don't get 15--you get an error. Cobra is not loosey goosey.

Two, it matches the Python semantics which are known from experience to work well and without annoyance/hindrance to the developer. It's hard to justify deviating in light of that.

-Chuck

Re: MultiArg assignment

PostPosted: Sun Oct 12, 2008 7:35 pm
by hopscc
No, as is rhs has to be a list/array/string (actually anything thats compilable to a numeric indexer)

I've not looked at this stage whats required for handling an unadorned comma separated literal/identifier stream since its a niche case and
doable via a literal list/array anyway

lhs/rhs matching count:
on one: As mentioned I dont disagree (strongly enough anyway) for the greater lhs case
Code: Select all
a,b,c=[1,2]

However
Code: Select all
a,b,c = [1,2,3,4]

isnt an out of range case (compile time or runtime)
on two: python semantics works but I'd disagree about the developer annoyance (for the lesser lhs length case) and that
its not possible to do better (less hindrance) than pythons nitpicking for that case.
Anything additional come to mind?

Re: MultiArg assignment

PostPosted: Mon Oct 13, 2008 1:40 am
by Charles
-- Regarding "a, b = c, d", one possible implementation is to simply have the parser create a list out of "c, d" for now since a list rhs is working.

-- Regarding having too few targets on the lhs:

* In my own Python coding, it's rarely the case that I have four items in the list, but I only want items 1 and 2

* Cobra and Python have slicing. For those cases where you want a portion of the list, it's easy to slap a "[:n]" on the end.

* In some cases, you'll want discontiguous items anyway in which case this "shortcut" doesn't help.

-- I'm surprised that if having to slice the list is annoying, you don't find having to wrap "c, d" in brackets to also be annoying. If you forget to do it, you have to cursor back to "c".