Forum: Ruby-core [ruby-trunk - Feature #6668][Open] Multiple assignment should not return an Array object

Posted by Charles Nutter (headius)
on 2012-06-29 19:11
(Received via mailing list)
Issue #6668 has been reported by headius (Charles Nutter).

----------------------------------------
Feature #6668: Multiple assignment should not return an Array object
https://bugs.ruby-lang.org/issues/6668

Author: headius (Charles Nutter)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


Currently, when doing multiple assignment, the entire expression must 
return the right-hand side as an array.

system ~ $ ruby -e "ret = (a, b, c = 1, 2, 3); p ret"
[1, 2, 3]

This is an artifact of MRI's implementation, since multiple assignment 
was traditionally implemented by taking the array node on the right-hand 
side, standing it up as a full Ruby Array, and then peeling elements off 
for assignment on the left-hand side. It is also a performance issue, 
since it requires constructing the RHS array even when it is never used 
(unless you are able to do various compiler tricks). I propose removing 
it.

Justification:

* The feature is rarely used; most people don't even know it exists.
* The impact of creating the RHS array is significant; JRuby can 
optimize it away in cases where the line is not used as an expression, 
and the performance difference is huge: https://gist.github.com/3019255
* It is counter-intuitive to have an automatic performance hit just from 
grouping assignments. "a,b = 1,2" should have the exact same performance 
as "a = 1; b = 2"

Note that while JRuby can eliminate the array creation in non-expression 
cases, those are somewhat rare since many times masgn is used at the end 
of a method body, as for initializers:

class Foo
  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end
end

JRuby and other implementations may get smart enough in our optimizers 
to eliminate the array in all cases where it's not needed, but this is a 
very large burden on the optimization subsystem. It may also not be 
possible to do in all cases (or not possible to do in even a majority of 
cases).

Multiple assignment should not return RHS as an array. I do not care 
what it returns.
Posted by Charles Nutter (headius)
on 2012-09-19 09:08
(Received via mailing list)
Issue #6668 has been updated by headius (Charles Nutter).


Ping!
----------------------------------------
Feature #6668: Multiple assignment should not return an Array object
https://bugs.ruby-lang.org/issues/6668#change-29507

Author: headius (Charles Nutter)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


Currently, when doing multiple assignment, the entire expression must 
return the right-hand side as an array.

system ~ $ ruby -e "ret = (a, b, c = 1, 2, 3); p ret"
[1, 2, 3]

This is an artifact of MRI's implementation, since multiple assignment 
was traditionally implemented by taking the array node on the right-hand 
side, standing it up as a full Ruby Array, and then peeling elements off 
for assignment on the left-hand side. It is also a performance issue, 
since it requires constructing the RHS array even when it is never used 
(unless you are able to do various compiler tricks). I propose removing 
it.

Justification:

* The feature is rarely used; most people don't even know it exists.
* The impact of creating the RHS array is significant; JRuby can 
optimize it away in cases where the line is not used as an expression, 
and the performance difference is huge: https://gist.github.com/3019255
* It is counter-intuitive to have an automatic performance hit just from 
grouping assignments. "a,b = 1,2" should have the exact same performance 
as "a = 1; b = 2"

Note that while JRuby can eliminate the array creation in non-expression 
cases, those are somewhat rare since many times masgn is used at the end 
of a method body, as for initializers:

class Foo
  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end
end

JRuby and other implementations may get smart enough in our optimizers 
to eliminate the array in all cases where it's not needed, but this is a 
very large burden on the optimization subsystem. It may also not be 
possible to do in all cases (or not possible to do in even a majority of 
cases).

Multiple assignment should not return RHS as an array. I do not care 
what it returns.
Posted by SASADA Koichi (Guest)
on 2012-09-19 12:39
(Received via mailing list)
(2012/09/19 0:08), headius (Charles Nutter) wrote:
> This is an artifact of MRI's implementation, since multiple assignment was 
traditionally implemented by taking the array node on the right-hand side, 
standing it up as a full Ruby Array, and then peeling elements off for assignment 
on the left-hand side. It is also a performance issue, since it requires 
constructing the RHS array even when it is never used (unless you are able to do 
various compiler tricks). I propose removing it.

FYI, from 1.9 the Array for RHS is not generated if it is not needed.

# not generated
a, b = c, d
a, b, c = d, e

# generated
a = b, c
a = b, c, d

I remain the spec because of compatibility.
#=> go to matz issue.

As you say the case which need to generate an array are not major case,
it is not performance problem in my opinion.

Thanks,
Koichi
Posted by Charles Nutter (headius)
on 2012-09-20 03:27
(Received via mailing list)
On Wed, Sep 19, 2012 at 3:38 AM, SASADA Koichi <ko1@atdot.net> wrote:
> FYI, from 1.9 the Array for RHS is not generated if it is not needed.
>
> # not generated
> a, b = c, d
> a, b, c = d, e

system ~/projects/jruby $ ruby-1.9.3 -e "def foo(c, d); a, b = c, d;
end; p foo 1, 2"
[1, 2]

system ~/projects/jruby $ ruby-1.9.3 -e "def foo(d, e); a, b, c = d,
e; end; p foo 1, 2"
[1, 2]

Perhaps by not needed you mean "not used in an expression"?

> # generated
> a = b, c
> a = b, c, d
>
> I remain the spec because of compatibility.
> #=> go to matz issue.
>
> As you say the case which need to generate an array are not major case,
> it is not performance problem in my opinion.

I disagree. For example, the following case would make instance
variable initialization much cheaper if the array did not have to be
constructed:

def initialize(a, b, c)
  @a, @b, @c = a, b, c
end

As above, since this line is the return value from the method, an
array would be created that nobody ever uses. There are many similar
cases where multiple assignment just happens to be the last line of a
method but nobody cares about the Array result...so it is wasted
effort to create it.

- Charlie
Posted by Charles Nutter (headius)
on 2012-10-14 21:55
(Received via mailing list)
Issue #6668 has been updated by headius (Charles Nutter).


I thought I replied to ko1, but must not have.

I believe MRI is using the same trick JRuby is...specifically, when the 
masgn's result is not used, it is not created. However, that does not 
help cases where masgn happens to be the last line in a method but its 
result is not used.

For example, the first case cannot optimize the masgn array away, but 
the second case can. The difference on even this small test is almost 2x 
GC runs:

system ~/projects/jruby $ ruby-2.0.0 -e "GC::Profiler.enable; class A; 
def initialize(a, b); @a, @b = a, b; end; end; 100000.times {A.new(1, 
2)}; GC::Profiler.report"
GC 17 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1               0.012               187520               701760 
17544         0.25600000000000100453
    2               0.014               187520               701760 
17544         0.23500000000000081934
    3               0.017               187440               701760 
17544         0.22700000000000150613
    4               0.020               187440               701760 
17544         0.23100000000000203704
    5               0.023               187440               701760 
17544         0.23700000000000109868
    6               0.025               187440               701760 
17544         0.22199999999999997513
    7               0.028               187440               701760 
17544         0.20999999999999838241
    8               0.031               187440               701760 
17544         0.23499999999999909850
    9               0.033               187440               701760 
17544         0.24400000000000116041
   10               0.036               187440               701760 
17544         0.22400000000000197531
   11               0.039               187440               701760 
17544         0.22599999999999703659
   12               0.041               187440               701760 
17544         0.22099999999999897504
   13               0.044               187440               701760 
17544         0.19999999999999878986
   14               0.046               187440               701760 
17544         0.20900000000000085176
   15               0.049               187440               701760 
17544         0.20699999999999885159
   16               0.052               187440               701760 
17544         0.23900000000000309885

system ~/projects/jruby $ ruby-2.0.0 -e "GC::Profiler.enable; class A; 
def initialize(a, b); @a, @b = a, b; nil; end; end; 100000.times 
{A.new(1, 2)}; GC::Profiler.report"
GC 9 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1               0.012               187400               701760 
17544         0.26500000000000134559
    2               0.017               187400               701760 
17544         0.28699999999999903366
    3               0.021               187360               701760 
17544         0.23799999999999862932
    4               0.025               187360               701760 
17544         0.22500000000000297540
    5               0.030               187360               701760 
17544         0.20799999999999985167
    6               0.034               187360               701760 
17544         0.20599999999999785150
    7               0.038               187360               701760 
17544         0.20499999999999685141
    8               0.042               187360               701760 
17544         0.22099999999999897504

For a result that is used so rarely, it seems a shame to require masgn 
to always return an array when used as an expression.
----------------------------------------
Feature #6668: Multiple assignment should not return an Array object
https://bugs.ruby-lang.org/issues/6668#change-30666

Author: headius (Charles Nutter)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


Currently, when doing multiple assignment, the entire expression must 
return the right-hand side as an array.

system ~ $ ruby -e "ret = (a, b, c = 1, 2, 3); p ret"
[1, 2, 3]

This is an artifact of MRI's implementation, since multiple assignment 
was traditionally implemented by taking the array node on the right-hand 
side, standing it up as a full Ruby Array, and then peeling elements off 
for assignment on the left-hand side. It is also a performance issue, 
since it requires constructing the RHS array even when it is never used 
(unless you are able to do various compiler tricks). I propose removing 
it.

Justification:

* The feature is rarely used; most people don't even know it exists.
* The impact of creating the RHS array is significant; JRuby can 
optimize it away in cases where the line is not used as an expression, 
and the performance difference is huge: https://gist.github.com/3019255
* It is counter-intuitive to have an automatic performance hit just from 
grouping assignments. "a,b = 1,2" should have the exact same performance 
as "a = 1; b = 2"

Note that while JRuby can eliminate the array creation in non-expression 
cases, those are somewhat rare since many times masgn is used at the end 
of a method body, as for initializers:

class Foo
  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end
end

JRuby and other implementations may get smart enough in our optimizers 
to eliminate the array in all cases where it's not needed, but this is a 
very large burden on the optimization subsystem. It may also not be 
possible to do in all cases (or not possible to do in even a majority of 
cases).

Multiple assignment should not return RHS as an array. I do not care 
what it returns.
Posted by matz (Yukihiro Matsumoto) (Guest)
on 2012-10-15 08:30
(Received via mailing list)
Issue #6668 has been updated by matz (Yukihiro Matsumoto).

Status changed from Open to Rejected
Assignee set to matz (Yukihiro Matsumoto)

Changing return value from massign would be agaist 2.0 compatibility 
policy.  Maybe in 3.0.
Method inlining in JRuby would help compatibility here as well, wouldn't 
it?

Matz.


----------------------------------------
Feature #6668: Multiple assignment should not return an Array object
https://bugs.ruby-lang.org/issues/6668#change-30718

Author: headius (Charles Nutter)
Status: Rejected
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category:
Target version:


Currently, when doing multiple assignment, the entire expression must 
return the right-hand side as an array.

system ~ $ ruby -e "ret = (a, b, c = 1, 2, 3); p ret"
[1, 2, 3]

This is an artifact of MRI's implementation, since multiple assignment 
was traditionally implemented by taking the array node on the right-hand 
side, standing it up as a full Ruby Array, and then peeling elements off 
for assignment on the left-hand side. It is also a performance issue, 
since it requires constructing the RHS array even when it is never used 
(unless you are able to do various compiler tricks). I propose removing 
it.

Justification:

* The feature is rarely used; most people don't even know it exists.
* The impact of creating the RHS array is significant; JRuby can 
optimize it away in cases where the line is not used as an expression, 
and the performance difference is huge: https://gist.github.com/3019255
* It is counter-intuitive to have an automatic performance hit just from 
grouping assignments. "a,b = 1,2" should have the exact same performance 
as "a = 1; b = 2"

Note that while JRuby can eliminate the array creation in non-expression 
cases, those are somewhat rare since many times masgn is used at the end 
of a method body, as for initializers:

class Foo
  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end
end

JRuby and other implementations may get smart enough in our optimizers 
to eliminate the array in all cases where it's not needed, but this is a 
very large burden on the optimization subsystem. It may also not be 
possible to do in all cases (or not possible to do in even a majority of 
cases).

Multiple assignment should not return RHS as an array. I do not care 
what it returns.
Posted by Charles Nutter (headius)
on 2012-10-15 19:11
(Received via mailing list)
Issue #6668 has been updated by headius (Charles Nutter).


Method inlining could help if we do it before handing off to the JVM, 
since we'd see that masgn result is not used...but that's still pretty 
far away from reality. The JVM might be able to eliminate the array 
allocation, but it's a very complicated operation and it will be 
difficult to see that it is zero-sum.
----------------------------------------
Feature #6668: Multiple assignment should not return an Array object
https://bugs.ruby-lang.org/issues/6668#change-30787

Author: headius (Charles Nutter)
Status: Rejected
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category:
Target version:


Currently, when doing multiple assignment, the entire expression must 
return the right-hand side as an array.

system ~ $ ruby -e "ret = (a, b, c = 1, 2, 3); p ret"
[1, 2, 3]

This is an artifact of MRI's implementation, since multiple assignment 
was traditionally implemented by taking the array node on the right-hand 
side, standing it up as a full Ruby Array, and then peeling elements off 
for assignment on the left-hand side. It is also a performance issue, 
since it requires constructing the RHS array even when it is never used 
(unless you are able to do various compiler tricks). I propose removing 
it.

Justification:

* The feature is rarely used; most people don't even know it exists.
* The impact of creating the RHS array is significant; JRuby can 
optimize it away in cases where the line is not used as an expression, 
and the performance difference is huge: https://gist.github.com/3019255
* It is counter-intuitive to have an automatic performance hit just from 
grouping assignments. "a,b = 1,2" should have the exact same performance 
as "a = 1; b = 2"

Note that while JRuby can eliminate the array creation in non-expression 
cases, those are somewhat rare since many times masgn is used at the end 
of a method body, as for initializers:

class Foo
  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end
end

JRuby and other implementations may get smart enough in our optimizers 
to eliminate the array in all cases where it's not needed, but this is a 
very large burden on the optimization subsystem. It may also not be 
possible to do in all cases (or not possible to do in even a majority of 
cases).

Multiple assignment should not return RHS as an array. I do not care 
what it returns.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.