||= with 1.8 and 1.9?

On Wed, Aug 26, 2009 at 5:23 PM, David A. Black[email protected]
wrote:

Matz’s characterization of it to me at RubyConf (or somewhere) was:

x ||= y same as x || x = y

Yeah, that version matches my mental model.

x ||= y
x = x || y
x || x = y

x += y
x = x + y
x + x = y # :slight_smile:

o.x ||= y
o.x = o.x || y
# .x= is always called
o.x || o.x = y
# .x= is not always called

o.x += y
o.x = o.x + y

Then maybe ||= and += should be split apart in rubyspec:
describe “var += expr” it “is equivalent to ‘var = var op expr’”
describe “var ||= expr” it “is equivalent to ‘var || var = expr’”

On Wed, Aug 26, 2009 at 5:23 PM, David A. Black[email protected]
wrote:

It isn’t, though, at least in the ||= case (see Joel W.'s post).
Matz’s characterization of it to me at RubyConf (or somewhere) was:

x ||= y same as x || x = y

It’s approximately the same as certainly closer than x = x || y

There’s a difference in what happens if x is not previously defined


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Hi,

In message “Re: ||= with 1.8 and 1.9 ?”
on Thu, 27 Aug 2009 01:20:20 +0900, Rick DeNatale
[email protected] writes:

|a = b = c
|
| is treated the same as
|
|b = c; a = c
|
|in other words the result of the b= is ignored.

No,

a = b = c

is parsed as

a = (b = c)

so, result of the latter assignment is used for the former assignment.
The point is when b here is an attribute assignment (e.g. foo.b = c),
the result value from the setter method (b=) is ignored.

|That’s why sending :bar= is giving the result of the method.
|
|As for why Ruby1.9 is treating the ||= form differently, I haven’t
|figured that out.
|
|
|
|–
|Rick DeNatale
|
|Blog: http://talklikeaduck.denhaven2.com/
|Twitter: http://twitter.com/RickDeNatale
|WWR: http://www.workingwithrails.com/person/9021-rick-denatale
|LinkedIn: http://www.linkedin.com/in/rickdenatale
|

Hi –

On Thu, 27 Aug 2009, Rick DeNatale wrote:

On Wed, Aug 26, 2009 at 5:23 PM, David A. Black[email protected] wrote:

It isn’t, though, at least in the ||= case (see Joel W.'s post).
Matz’s characterization of it to me at RubyConf (or somewhere) was:

 x ||= y  same as   x || x = y

It’s approximately the same as certainly closer than x = x || y

There’s a difference in what happens if x is not previously defined

True. Maybe this?

defined?(x) && x || x = y

David

Hi –

On Thu, 27 Aug 2009, [email protected] wrote:

On Wed, Aug 26, 2009 at 3:46 PM, Rick DeNatale[email protected] wrote:

Right, the question is why in Ruby 1.9 is using the ‘not a test’
returned from the setter method in the case of ||= unlike Ruby 1.8.x
and like itself in the = case:

According the rubyspec project:

language/variables_spec.rb:
describe “Operator assignment ‘var op= expr’” do
it “is equivalent to ‘var = var op expr’” do

It isn’t, though, at least in the ||= case (see Joel W.'s post).
Matz’s characterization of it to me at RubyConf (or somewhere) was:

x ||= y same as x || x = y

David

Hi,

In message “Re: ||= with 1.8 and 1.9 ?”
on Thu, 27 Aug 2009 06:23:01 +0900, “David A. Black”
[email protected] writes:

|> According the rubyspec project:
|>
|> language/variables_spec.rb:
|> describe “Operator assignment ‘var op= expr’” do
|> it “is equivalent to ‘var = var op expr’” do
|
|It isn’t, though, at least in the ||= case (see Joel W.'s post).
|Matz’s characterization of it to me at RubyConf (or somewhere) was:
|
| x ||= y same as x || x = y

Basically, “var op= expr” works like “var = var op expr” but left hand
side expression (var) is evaluated only once. For ||=, it is same as

x = (x || y)

but

x || (x = y)

is semantically same (well, almost).

          matz.

Hi –

On Thu, 27 Aug 2009, Yukihiro M. wrote:

|
but

x || (x = y)

is semantically same (well, almost).

The hash case, though, definitely points to x || (x = y):

h = Hash.new(5)
=> {}

h[:x] = (h[:x] || 1)
=> 5

h
=> {:x=>5}

h[:z] || (h[:z] = 1)
=> 5

h
=> {:x=>5}

h[:y] ||= 1
=> 5

h
=> {:x=>5}

David

I’ve never understood ||=. As a result, I would never use it in my
code. As far as I’m concerned, I can explicitly write what I want
rather than trust some unpredictable, quirky short hand operator.

Brian C. wrote:

The method name is ‘x=’ and it was called using ‘obj.x=’. Where’s the
sugar?

The parentheses in (10) are not delimiting arguments of a method call;
they are just bracketing a value expression. Note:

class Foo; def bar=(x,y,z); 123; end; end
=> nil

Foo.new.send(:bar=,7,8,9)
=> 123

Foo.new.bar=(7,8,9)
SyntaxError: compile error
(irb):3: syntax error, unexpected ‘,’, expecting ‘)’
Foo.new.bar=(7,8,9)
^
from (irb):3
from :0

Similarly:

Foo.new.bar= 7,8,9
ArgumentError: wrong number of arguments (1 for 3)
from (irb):4:in `bar=’
from (irb):4
from :0

Wow. Thanks for the explanation.

.
.
.
.
.
.
.
.

.
.

On Wed, Aug 26, 2009 at 7:00 PM, Yukihiro M.[email protected]
wrote:

|
|in other words the result of the b= is ignored.

No,

a = b = c

is parsed as

a = (b = c)

Yes, I was speaking a bit loosely and was trying to say just what you
said next

so, result of the latter assignment is used for the former assignment.
The point is when b here is an attribute assignment (e.g. foo.b = c),
the result value from the setter method (b=) is ignored.

And I think that the really important point here is that

a.b ||= c

should have have the same effect as

a.b || a.b = c

And that it’s surprising that in Ruby 1.9 it doesn’t

puts RUBY_VERSION

class OrOrEquals
def test
@test
end

def test=(test)
@test = test
‘not test’
end
end

o = OrOrEquals.new

direct = o.test = ‘a test’
p direct
o.test = nil
with_oror = o.test ||= ‘a test’
p with_oror

with_or_or_assign = o.test || o.test = “a test”
p with_or_or_assign

$ multiruby or_or_equals.rb
/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:144:
warning: /Users/rick/.gem/ruby/1.8/specifications: Permission denied

VERSION = 1.8.6-p368
CMD = ~/.multiruby/install/1.8.6-p368/bin/ruby or_or_equals.rb

1.8.6
“a test”
“a test”
“a test”

RESULT = 0

VERSION = 1.8.7-p160
CMD = ~/.multiruby/install/1.8.7-p160/bin/ruby or_or_equals.rb

1.8.7
“a test”
“a test”
“a test”

RESULT = 0

VERSION = 1.9.1-p0
CMD = ~/.multiruby/install/1.9.1-p0/bin/ruby or_or_equals.rb

1.9.1
“a test”
“not test”
“a test”

RESULT = 0


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale