Ruby Conditional-Assignment and Private Methods
That looks like a bug.
UPDATE: The bug was fixed in trunk, and is slated for back porting to 2.1 and 2.0.
Note that the problem is more general than that, it is broken for all abbreviated assignments, not just conditional abbreviated assignments:
private def foo=(*) end
public def foo; 0 end
self.foo = 42
self.foo += 42
# private method `foo=' called for main:Object (NoMethodError)
private :foo
self.foo += 42
# private method `foo' called for main:Object (NoMethodError)
||=' operator in Ruby
It's an assignment operator for 'Conditional Assignment'
See here -> http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators
Conditional assignment:
x = find_something() #=>nil
x ||= "default" #=>"default" : value of x will be replaced with "default", but only if x is nil or false
x ||= "other" #=>"default" : value of x is not replaced if it already is other than nil or false
Operator ||= is a shorthand form of the expression:
x = x || "default"
EDIT:
After seeing OP's edit, the example is just an extension of this, meaning:
car = method_1 || method_2 || method_3 || method_4
Will assign the first non-nil or non-false return value of method_1, method_2, method_3, method_4 (in that order) to car
or it'll retain its old value.
What does ||= (or-equals) mean in Ruby?
This question has been discussed so often on the Ruby mailing-lists and Ruby blogs that there are now even threads on the Ruby mailing-list whose only purpose is to collect links to all the other threads on the Ruby mailing-list that discuss this issue.
Here's one: The definitive list of ||= (OR Equal) threads and pages
If you really want to know what is going on, take a look at Section 11.4.2.3 "Abbreviated assignments" of the Ruby Language Draft Specification.
As a first approximation,
a ||= b
is equivalent to
a || a = b
and not equivalent to
a = a || b
However, that is only a first approximation, especially if a
is undefined. The semantics also differ depending on whether it is a simple variable assignment, a method assignment or an indexing assignment:
a ||= b
a.c ||= b
a[c] ||= b
are all treated differently.
Is the ruby operator ||= intelligent?
This is extremely easy to test:
class MyCache
def initialize
@hash = {}
end
def []=(key, value)
puts "Cache key '#{key}' written"
@hash[key] = value
end
def [](key)
puts "Cache key '#{key}' read"
@hash[key]
end
end
Now simply try the ||=
syntax:
cache = MyCache.new
cache["my key"] ||= "my value" # cache value was nil (unset)
# Cache key 'my key' read
# Cache key 'my key' written
cache["my key"] ||= "my value" # cache value is already set
# Cache key 'my key' read
So we can conclude that no assignment takes place if the cache key already exists.
The following extract from the Rubyspec shows that this is by design and should not be dependent on the Ruby implementation:
describe "Conditional operator assignment 'obj.meth op= expr'" do
# ...
it "may not assign at all, depending on the truthiness of lhs" do
m = mock("object")
m.should_receive(:foo).and_return(:truthy)
m.should_not_receive(:foo=)
m.foo ||= 42
m.should_receive(:bar).and_return(false)
m.should_not_receive(:bar=)
m.bar &&= 42
end
# ...
end
In the same file, there is a similar spec for []
and []=
that mandates identical behaviour.
Although the Rubyspec is still a work in progress, it has become clear that the major Ruby implementation projects intend to comply with it.
Expansion with conditional ternary operator
Unfortunately this isn’t currently possible. The …
spread syntax, like its name tells us, is a part of the syntax of the language and not a ‘normal’ operator that deals with expressions (à la +
or typeof
). The ternary operator needs expressions after the ?
and :
, so you can’t use the syntax in those spots.
You’ll have to do e.g.
condition
? console.log(…)
: console.log(…)
What does the |= operator do in Java?
|=
is a bitwise-OR-assignment operator. It takes the current value of the LHS, bitwise-ors the RHS, and assigns the value back to the LHS (in a similar fashion to +=
does with addition).
For example:
foo = 32; // 32 = 0b00100000
bar = 9; // 9 = 0b00001001
baz = 10; // 10 = 0b00001010
foo |= bar; // 32 | 9 = 0b00101001 = 41
// now foo = 41
foo |= baz; // 41 | 10 = 0b00101011 = 43
// now foo = 43
Getting confused with == and = in if statement
Because the "result" of an assignment is the value assigned... so it's still a boolean
expression in the second case. if
expressions require the condition to be a boolean
expression, which is satisfied by the second but not the first. Effectively, your two snippets are:
int a;
a = 1;
if (a) { }
and
boolean b;
b = true;
if (b) { }
Is it clear from that expansion that the second version will compile but not the first?
This is one reason not to do comparisons with true and false directly. So I would always just write if (b)
instead of if (b == true)
and if (!b)
instead of if (b == false)
. You still get into problems with if (b == c
) when b
and c
are boolean
variables, admittedly - a typo there can cause an issue. I can't say it's ever happened to me though.
EDIT: Responding to your edit - assignments of all kinds can be used in if
statements - and while
loops etc, so long as the overall condition expression is boolean
. For example, you might have:
String line;
while ((line = reader.readLine()) != null)
{
// Do something with a line
}
While I usually avoid side-effects in conditions, this particular idiom is often useful for the example shown above, or using InputStream.read
. Basically it's "while the value I read is useful, use it."
How to build a conditional assignment in bash?
As per Jonathan's comment:
variable=$(( 1 == 1 ? 1 : 0 ))
EDIT:
I revised the original answer which just echo
'd the value of the condition operator, it didn't actually show any assignment.
Related Topics
Which Global Variable Is for Last Expression
How to Http Post Stream Data from Memory in Ruby
Ruby 1.9 - No Such File to Load 'Win32/Open3'
How to Efficiently Extract Repeated Elements in a Ruby Array
Validating Phone Number in Ruby
Ruby Open-Uri Can't Open Url (M1 MAC)
Why Does My Recursive Method from Helper Not Return Every Value
Why Can't I Change the Value of Self
Gem Install Therubyracer -V 0.11.4 Fails on Os X 10.10
How to Convert This Ruby String into an Array
Differencebetween a Constant and a Variable in Ruby
Why Rails Can Use 'If' as Hash Key But Not in Ruby
Ruby on Rails: Fully Functional Tableless Model
Ruby#Index Method VS Binary Search
What Is the Ruby Equivalent of Preg_Quote()
Iterate Through Array of Hashes in Ruby
How to Use Ruby Date Constants Gregorian, Julian, England and Even Italy