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?
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?
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.
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
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
.
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.
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