The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
x ||= y, Redux

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Rick DeNatale

Posts: 269
Nickname: rdenatale
Registered: Sep, 2007

Rick DeNatale is a consultant with over three decades of experience in OO technology.
x ||= y, Redux Posted: Apr 26, 2008 11:18 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Rick DeNatale.
Original Post: x ||= y, Redux
Feed Title: Talk Like A Duck
Feed URL: http://talklikeaduck.denhaven2.com/articles.atom
Feed Description: Musings on Ruby, Rails, and other topics by an experienced object technologist.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Rick DeNatale
Latest Posts From Talk Like A Duck

Advertisement
A while back there was quite a thread on the Ruby-lang mailing list about the real semantics of the expression.
a[x] ||= some_value

In many books and articles on Ruby the form:

a <op>= b

Where <op> is an operator like + Is described as syntactic sugar:

a = a <op> b

While this is true in most cases, it isn’t’ true if the operator is ||.

This comes to light when the left hand side is a method call, to an accessor, or accessor-like method. For example

h = Hash.new("hello")
h[:fred] ||= ""
h #=> {}

Some find it surprising that the assignment doesn’t cause the hash to have :fred as a key. What this code snippet shows is that the assignment doesn’t actually assign anything if the left hand expression returns a logically true value. A Hash with a default value will return the default value when accessed by any key which is not present in the hash. Since h[:fred] returns the default value, the assignment doesn’t happen.

This affects any object which has ‘accessor’ methods. Here’s a class cooked up just to explore this aspect of Ruby.

class ChattyCathy

  def initialize(x=nil)
    @x = x
    puts "created x is now #{x.inspect}"
  end

  def x
    puts "x read x is #{@x.inspect}"
    @x
  end

  def x=(val)
    puts "x written, now #{val.inspect}"
    @x = val
  end
end

The purpose of this class is simply to let us see exactly when the x attribute is read and written. Now if we run this code

c = ChattyCathy.new(42)
puts "about to evaluate c.x ||= 43"
c.x ||= 43
c = ChattyCathy.new
puts "about to evaluate c.x ||= 43"
c.x ||= 43

We get the following output:

created x is now 42 about to evaluate c.x ||= 43 x read x is 42 created x is now nil about to evaluate c.x ||= 43 x read x is nil x written, now 43

Which clearly illustrates just when the assignment actually happens.

The real expansion of x ||= y

Matz explains that the real expansion of x ||= y is:

x || x = y

The expectation that x ||= y is the same as x = x || y, does seem reasonable to someone ‘coming from’ C or one of it’s derivative languages. As far as I can determine, C introduced the notion of assignment operators like += and -=. And K&R defined these assignment operators as a shorthand for x = x + y, etc.

On the other hand, although C has logical operators || and && which, like Ruby have ‘short-circuit’ evaluation, it doesn’t allow ||=, or &&= as assignment operators.

Since || is a ‘short-circuit’ boolean operator, the left hand operand expression is only evaluated if the right hand operand expression evaluates to a logically false value, i.e. either nil or false.

The way that Matz included ||= as an assignment operator makes perfect sense to me. The ||= assignment operator reserves the short-circuit nature of ||.

So what about x &&= y

Although I haven’t seen this discussed anywhere, &&= in Ruby has similar behavior:

c = ChattyCathy.new
puts "about to evaluate c.x &&= true"
c.x &&= true
puts "about to evaluate c.x = \"hi\""
c.x = "Hi"
puts "about to evaluate c.x &&= true"
c.x &&= true
created x is now nil about to evaluate c.x &&= true x read x is nil about to evaluate c.x = “hi” x written, now “Hi” about to evaluate c.x &&= true x read x is “Hi” x written, now true

So the expansion of x &&= y is x && x = y

Read: x ||= y, Redux

Topic: Tweet Nodes Previous Topic   Next Topic Topic: Monkey Patching Core Functionality == BAD, BAD, BAD

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use