0

Possible Duplicate:
What does ||= (or equals) mean in Ruby?

Out on the internet I've seen the following syntax in Ruby/Rails:

user ||= User.new

I'm a newbie and I can't parse this. Can someone explain to me what the "||=" operator does?

Community
  • 1
  • 1
dB'
  • 7,838
  • 15
  • 58
  • 101
  • Ah, sorry about that. I tried putting '||=' into the search box here on SO but nothing came up. Maybe my query was being interpreted as a couple of boolean operators rather than a string? Am I searching the wrong way? – dB' Aug 14 '12 at 18:54
  • 2
    I am not sure how SO handles characters like ||=. I searched using the English words or equals. – Aaron Kurtzhals Aug 14 '12 at 18:57
  • I'll try that next time. Thanks. – dB' Aug 14 '12 at 18:58

5 Answers5

4

If user is already set this does nothing, otherwise it will assign a new User object (created with User.new).

According to David A. Black, author of "The Well-Grounded Rubyist":

x ||= y means: x || x = y

The difference is that x ||= y won't complain if x is undefined, whereas if you type x || x = y and there's no x in scope, it will.

For some added details, here's the relevant part of parse.y:

| var_lhs tOP_ASGN command_call
{
  /*%%%*/
  value_expr($3);
  if ($1) {
    ID vid = $1->nd_vid;
    if ($2 == tOROP) {
      $1->nd_value = $3;
      $$ = NEW_OP_ASGN_OR(gettable(vid), $1);
      if (is_asgn_or_id(vid)) {
        $$->nd_aid = vid;
      }
    }
    else if ($2 == tANDOP) {
      $1->nd_value = $3;
      $$ = NEW_OP_ASGN_AND(gettable(vid), $1);
    }
    else {
      $$ = $1;
      $$->nd_value = NEW_CALL(gettable(vid), $2, NEW_LIST($3));
    }
  }

NEW_OP_ASGN_OR is defined in node.h:

#define NEW_OP_ASGN_OR(i,val) NEW_NODE(NODE_OP_ASGN_OR,i,val,0)

NEW_NODE looks like this:

#define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))

Looking for NODE_OP_ASGN_OR leads to compile.c, where the interesting part looks like this:

case NODE_OP_ASGN_OR:{
   LABEL *lfin = NEW_LABEL(nd_line(node));
   LABEL *lassign;

   if (nd_type(node) == NODE_OP_ASGN_OR) {
     LABEL *lfinish[2];
     lfinish[0] = lfin;
     lfinish[1] = 0;
     defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
     lassign = lfinish[1];
     if (!lassign) {
       lassign = NEW_LABEL(nd_line(node));
     }
     ADD_INSNL(ret, nd_line(node), branchunless, lassign);
   }
   else {
     lassign = NEW_LABEL(nd_line(node));
   }

   COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
   ADD_INSN(ret, nd_line(node), dup);

   if (nd_type(node) == NODE_OP_ASGN_AND) {
     ADD_INSNL(ret, nd_line(node), branchunless, lfin);
   }
   else {
     ADD_INSNL(ret, nd_line(node), branchif, lfin);
   }

   ADD_INSN(ret, nd_line(node), pop);
   ADD_LABEL(ret, lassign);
   COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
   ADD_LABEL(ret, lfin);

   if (poped) {
     /* we can apply more optimize */
     ADD_INSN(ret, nd_line(node), pop);
   }
   break;
 }

I think this is more than I ever wanted to know about assignment in Ruby, but it was rather entertaining to look this up.

Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
2

It's basically a shortcut for:

user = user || User.new

or for better understanding:

if user.nil?
    user = User.new
end

I bet you've seen similar notations before with operators like '+'

i += 1

which can also be written out as:

i = i + 1
Radi
  • 696
  • 4
  • 11
0

The statement set user to itself (if it is already an existing object) or User.new (which will create a new user if user is null). It's a logical OR that will avoid having an assigned null user object.

The code is a shorthand for

user = user || User.new

If user is null, then user will be set to User.new.

0

This statement is equivalent to

user = user || User.new

which is equivalent of

user = user ? user : User.new

It will assign the value of User.new to the variable user if and only if user is nil. If it isn't, the contents of user will remain unchanged.

waldrumpus
  • 2,540
  • 18
  • 44
0

It's equivalent to user = user || User.new.

This relies on the short-circuiting behavior of the || operator. If the left side of the expression is true, then it doesn't matter what the right side will be, the overall expression will be true, so the operator "short-circuits" and stops evaluating. And rather than returning a boolean "true", the || operator returns the last value that it evaluated.

So, ||= is useful for assigning a default value. If user has a value, then user || User.new evaluates to user otherwise it evaluates to User.new which is the default value.

An equivalent block would be:

if user
    user = user
else 
    user = User.new
end 
Retsam
  • 30,909
  • 11
  • 68
  • 90