Ruby : Conditional initialization - ruby

I've read about conditional initialization in Ruby and
obj1 ||= Class1.new
is same as
obj1 ||obj1 = Class1.new
as everything is Ruby is an Object, I wonder why the following phrase raises a "NameError: undefined method or name...":
x || x = 10
but
x ||= 10
is a correct statement

In the first form, x is referenced first independently. Unlike the second form, x needs to be defined first or else it would raise an error.
> x = nil
=> nil
> x || x = 10
=> 10
The form x ||= 10 combines declaration and testing at the same time, so it doesn't generate an error whether x was already declared earlier or not.

defined?(x) || something
In your example, x does not exist. So you can't test what its' value is. Check to see whether it is defined. You can go further:
defined?(x) && x.nil? || x = 10
This will check to see if x is defined. If not, it will set x to 10. If x is defined, but has a nil value (also not useful), then x is also set to 10.

I've always thought of it as being equivalent to obj1 = obj1 || Class1.new, rather than obj1 || obj1 = Class1.new. This interpretation is more correct because it doesn't raise a NameError, and is consistent with the behavior of other operators which combine with =:
number = 1
number += 2 #=> 3
number -= 5 #=> -2
number *= 2 #=> -4
number /= 2 #=> -2
number **= 2 #=> 4
boolean = false
boolean ||= false #=> false
boolean ||= true #=> true
boolean &&= true #=> true
boolean &&= false #=> false
boolean &&= false #=> false
string = ""
string += "Hello" #=> "Hello"
string += ", world!" #=> "Hello, world!"
As for why obj1 || obj1 = Class1.new raises a NameError, it's because the part of that statement before the || operator is trying to reference obj1 before it's defined. obj1 = obj1 || Class1.new doesn't do that because it starts the assignment before referencing obj1.

Related

Need clarification on Ruby logical operators

Recently I started learning Ruby. I am practicing logical operators in irb and I got these results, which I don't understand. Can you please clarify these examples for me?
1 and 0
#=> 0
0 and 1
#=> 1
0 && 1
#=> 1
As opposed to other languages like C, in Ruby all values except for nil and false are considered “truthy”. This means, that all these values behave like true in the context of a boolean expression.
Ruby's boolean operators will not return true or false. Instead, they return the first operand that causes the evaluation of the condition to be complete (also known as short-circuit evaluation). For boolean and that means, it will either return the first “falsy” operand or the last one:
false && 1 # => false (falsy)
nil && 1 # => nil (falsy)
false && nil # => false (falsy)
1 && 2 # => 2 (truthy)
For boolean or that means, it will either return the first “truthy” operand or the last one:
false || 1 # => 1 (truthy)
nil || 1 # => 1 (truthy)
false || nil # => nil (falsy)
1 || 2 # => 1 (truthy)
This allows for some interesting constructs. It is a very common pattern to use || to set default values, for example:
def hello(name)
name = name || 'generic humanoid'
puts "Hello, #{name}!"
end
hello(nil) # Hello, generic humanoid!
hello('Bob') # Hello, Bob!
Another similar way to acheive the same thing is
name || (name = 'generic humanoid')
With the added benefit that if name is truthy, no assignment is performed at all. There is even a shortcut for this assignment of default values:
name ||= 'generic humanoid'
If you paid careful attention you will have noticed that this may cause some trouble, if one valid value is false:
destroy_humans = nil
destroy_humans ||= true
destroy_humans
#=> true
destroy_humans = false
destroy_humans ||= true
destroy_humans
#=> true, OMG run!
This is rarely the desired effect. So if you know that the values can only be a String or nil, using || and ||= is fine. If the variable can be false, you have to be more verbose:
destroy_humans = nil
destroy_humans = true if destroy_humans.nil?
destroy_humans
#=> true
destroy_humans = false
destroy_humans = true if destroy_humans.nil?
destroy_humans
#=> false, extinction of humanity digressed!
That was close! But wait, there is another caveat – specifically with the usage of and and or. These should never be used for boolean expressions, because they have very low operator precedence. That means they will be evaluated last. Consider the following examples:
is_human = true
is_zombie = false
destroy_human = is_human && is_zombie
destroy_human
#=> false
is_human = true
is_zombie = false
destroy_human = is_human and is_zombie
destroy_human
#=> true, Waaaah but I'm not a zombie!
Let me add some parentheses to clarify what's happening here:
destroy_human = is_human && is_zombie
# equivalent to
destroy_human = (is_human && is_zombie)
destroy_human = is_human and is_zombie
# equivalent to
(destroy_human = is_human) and is_zombie
So and and or are really just useful as “control-flow operators”, for example:
join_roboparty or fail 'forever alone :('
# this will raise a RuntimeError when join_roboparty returns a falsy value
join_roboparty and puts 'robotz party hard :)'
# this will only output the message if join_roboparty returns a truthy value
I hope that clarifies everything you need to know about these operators. It takes a bit of getting used to, because it differs from the way other languages handle it. But once you know how to use the different options, you've got some powerful tools at hand.
Both values are 'truthy' (in Ruby everything that isn't nil or false is truthy), so in all cases the second value is returned. On the contrary, if you use 'or', first value will be returned:
1 || 0 #=> 1
0 || 1 #=> 0
In Ruby both 0 and 1 is truth value. (Only nil and false are false value)
If both operands are truth value, and, && returns the last value.

Ruby: difference between &= and &&=

I have the impression I can use
bool &= true
# and
bool &&= true
# indifferently
Is there any difference between two? Is one solution unrecommended?
Actually
bool = true & false # false
So what's the difference between & and && in general? (I guess the same applies for ||)
Try the following:
x = 5
x |= 2
=> 7
|= and &= are equivalent to the bitwise x = x | 2 and x = x & 2
vs
x = 5
x ||= 2
=> 5
In the second statement, x ||= 2, it means x = 2 if x is nil, otherwise it's x.
( x = (x || 2) ; the expression x || 2 returns x if x is anything but nil otherwise it returns 2.
x ||= 'foo' is actually very common in Ruby (set x to foo is x is not already set)
x = (x & 3) (which is equivalent to x &= 3), returns 3 (the second operand) unless x is 0, it returns 0)
)
The same logic applies for & but it was easier to find an example on the top of my mind for |
=)
The main difference between the keywords is that the first | is a method, and can be redefined for a class, and the second || is not, and can be never defined as a method, and just used for language syntax, as you can see in example below:
Array.new.respond_to?( :| )
# => true
Array.new.respond_to?( :|| )
SyntaxError: (irb):35: syntax error, unexpected tOP_ASGN, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
So, when you have applied the #| method it is able to return a value that differs from true, or false. Although for ruby's TrueClass, and FalseClass those values are true or false, but other descendants could redefine the return value, however, for Array and Set classes it implements functions similar to boolean bitwise operation. So can be sure that the true or false class's methods return also true or false. Otherwise, the keyword || is real language boolean operator, however it operates with values true, and not-true, you can see it on example:
'value1' || 'value2'
# => "value1"
true || false
# => true
'value1' || false
# => "value1"
false || 'value2'
# => "value2"
The return valus is always subordinated to logical expression, but the values of it are, as I denoted above, true, and not-true. Therefore you see in example return values not only of true/false pair, but of the real variable values too, and you can use it as if conditional operators as follows:
'value1' || 'value2'
and
if 'value1'
'value1'
else
'value2'
end
will return the same value.
According the or-equal assignment we see the following:
A |= false
# NameError: uninitialized constant A
a |= false
# false
A ||= false
# => false
In first case we are able to split |= operation into the two: call to #| method, and to assign the result to the variable. In the second case the ruby interpreter sees the whole operator ||=, verifies weither it is nil or undefined, and if yes assign to the variable or to the const the expression result.
The pair &, && has the same explanation.
When you are only using the & operator on boolean values, then there is no difference to &&, but if you want to use it with functions that return a boolean value then there is a difference. Have a look at this code:
def side_effect(message="hello")
puts message
true
end
#writes "hello" 2 times to the console and then returns false
false & side_effect & side_effect
# just returns false without writing "hello" to the console.
false && side_effect && side_effect

How to increment an Integer variable by X without creating a new object instance

How can I increment an Integer variable by X without creating a new object instance?
+= does not work because:
ree-1.8.7-2010.02 > x = 1
1
ree-1.8.7-2010.02 > x.object_id
3
ree-1.8.7-2010.02 > x += 1
2
ree-1.8.7-2010.02 > x.object_id
5
You can't. Not in Ruby, and not in any other programming language I am aware of.
The object which represents the mathematical number 1 will always have the value 1. Mutating the object which represents the mathematical number 1 to suddenly have the value 2 would quite simply be insane, because now all of a sudden 1 + 1 == 4.
Extend your example for a moment. Try this:
x = 2
y = 1 + 1
x.object_id
y.object_id
Every unique number will have its own identity. Ruby's object orientedness goes a bit deeper than you will find with C++ and Java (both of those have the concept of primitives and classes).
What's important is that when you query x the second time for its value the value will be what you expect. Object identifiers don't really matter unless you are the garbage collector.
It gets worse with Bignums
begin
a = 1234567890
puts a.object_id
b = 1234567890
puts b.object_id
end
gave me
10605136
10604960
Execution time is really terrible even if just you organize a simple loop. Primitives shouldn't be ditched from Ruby.
(1..16000).each do
(1..16000).each do
end
end
This itself takes 30-40 seconds to complete (Lenovo T400, Virtualboxed Ubuntu), and you haven't even done something sophisticated.
You can use a helper class:
class Variable
def initialize value = nil
#value = value
end
attr_accessor :value
def method_missing *args, &blk
#value.send(*args, &blk)
end
def to_s
#value.to_s
end
# here's the increment/decrement part
def inc x = 1
#value += x
end
def dec x = 1
#value -= x
end
end
x = Variable.new 1
puts x #=> 1
puts x.object_id #=> 22456116 (or whatever)
x.inc
puts x #=> 2
puts x.object_id #=> 22456116
x.inc 3
puts x #=> 5
puts x.object_id #=> 22456116
More uses of "class Variable" here.

Ruby `when' keyword does not use == in case statement. What does it use?

x == User returns true, but case x statement does not run the block associated with User. What's happening here?
u = User.new
# => #<User:0x00000100a1e948>
x = u.class
# => User
x == User
# => true
case x
when User
puts "constant"
when "User"
puts "string"
else
puts "nothing?"
end
# => nothing?
Case comparisons use === rather than ==. For many objects the behaviour of === and == is the same, see Numeric and String:
5 == 5 #=> true
5 === 5 #=> true
"hello" == "hello" #=> true
"hello" === "hello" #=> true
But for other kinds of object === can mean many things, entirely depending on the receiver.
For the case of classes, === tests whether an object is an instance of that class:
Class === Class.new #=> true.
For Range it checks whether an object falls in that range:
(5..10) === 6 #=> true
For Procs, === actually invokes that Proc:
multiple_of_10 = proc { |n| (n % 10) == 0 }
multiple_of_10 === 20 #=> true (equivalent to multiple_of_10.call(20))
For other objects, check their definition of === to uncover their behaviour. It's not always obvious, but they usually make some kind of sense..
Here is an example putting it all together:
case number
when 1
puts "One"
when 2..9
puts "Between two and nine"
when multiple_of_10
puts "A multiple of ten"
when String
puts "Not a number"
end
See this link for more info: http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/
In case statement , the comparison is done using === operator.
So your code is translated to following:
case x
when User === x
puts "Constant"
when "User" === x
puts "string"
else
puts "nothing"
end
Different class define === in different way:
The Class class define === so that it tests whether the righthand operand (x)is an instance of the class named by the lefthand operand (User). So , It is not surprise that User === x will be evaluated as false. Instead, User === u (u = User.new) is true.
irb(main):001:0> class User
irb(main):002:1> end
=> nil
irb(main):003:0> u = User.new
=> #<User:0xb7a90cd8>
irb(main):004:0> User === u.class
=> false
irb(main):005:0> User === u
=> true

Is it possible to have class.property = x return something other than x?

Let's say I have a Ruby class:
class MyClass
def self.property
return "someVal"
end
def self.property=(newVal)
# do something to set "property"
success = true
return success # success is a boolean
end
end
If I try and do MyClass.property=x, the return value of the whole statement is always x. It is a convention in a lot of C-based/inspired languages to return a boolean "success" value - is it possible to do this for a setter using the "equals syntax" in Ruby?
Furthermore - if this isn't possible, why not? Is there any conceivable downside to allowing an "equals setter" operation return a value?
One downside is that you would break the chained assignment semantics:
$ irb
irb(main):001:0> x = y = 3
=> 3
irb(main):002:0> p x
3
=> nil
irb(main):003:0> p y
3
=> nil
irb(main):004:0>
Consider:
x = MyClass.property = 3
Then x would take true if this worked as you had expected (right-associativity). That could be a surprise for people using your interface and used to the typical semantics.
You also got me thinking about parallel assignment, eg:
x, y = 1, 2
Apparently the return value from that expression is implementation specific... I guess I won't be chaining parallel assignments :)
Nice question!
Like Martin says, this would break assignment chaining.
The way ruby assignment methods are defined to work expands MyClass.property = 3 to the equivalent of (lambda { |v| MyClass.send('property=', v); v })[3] (not really, but this shows how chaining works). The return value of the assignment is always the value assigned.
If you want to see the result of your MyClass#property= method, then use #send:
irb> o = Object.new
=> #<Object:0x15270>
irb> def o.x=(y)
irb> #x = y+1
irb> puts "y = #{y}, #x = ##x"
irb> true
irb> end
=> nil
irb> def o.x
irb> puts "#x = ##x"
irb> #x
irb> end
=> nil
irb> o.x = 4
y = 4, #x = 5
=> 4
irb> o.x
#x = 5
=> 5
irb> o.send('x=', 3)
y = 3, #x = 4
=> true
However, the ruby way to do this is with exceptions - if something goes wrong during
the assignment, raise an exception. Then all invokers must handle it if something goes
wrong, unlike a return value, which can be easily ignored:
# continued from above...
irb> def o.x=(y)
irb> unless y.respond_to? :> and (y > 0 rescue false)
irb> raise ArgumentError, 'new value must be > 0', caller
irb> end
irb> #x = y + 1
irb> puts "y = #{y}, #x = ##x"
irb> end
=> nil
irb> o.x = 4
y = 4, #x = 5
=> 4
irb> o.x = 0
ArgumentError: new value must be > 0
from (irb):12
from :0
irb> o.x = "3"
ArgumentError: new value must be > 0
from (irb):13
from :0
irb> o.x
#x = 5
=> 5
I'm not a Ruby expert but I'd say no for that case I'm afraid. A property setter is solely there to set the value of a private field, not to have any side effects like returning result codes.
If you want that functionality then forget the setter and write a new method called TrySetProperty or something which tries to set the property and returns a boolean.

Resources