This question already has answers here:
Ruby: "if !object.nil?" or "if object"
(5 answers)
Closed 8 years ago.
As the title, are the following two statements same:
if val
and
if !val.nil?
No.
2.0.0-p481 :001 > val = false
=> false
2.0.0-p481 :002 > val.nil?
=> false
In ruby, nil and false are both falsey, but only nil is nil.
No they both are different. Here is an example for you
irb(main):001:0> val = 10
=> 10
irb(main):002:0> if val
irb(main):003:1> puts"kranthi"
irb(main):004:1> end
kranthi
=> nil
irb(main):005:0> val = nil
=> nil
irb(main):006:0> if val
irb(main):007:1> puts"kranthi"
irb(main):008:1> end
=> nil
irb(main):009:0> val = "test"
=> "test"
irb(main):010:0> if val
irb(main):011:1> puts "kranthi"
irb(main):012:1> end
kranthi
=> nil
Related
I was curious about what the difference is between the two.
irb(main):001:0> require 'active_support/core_ext'
=> true
irb(main):002:0> 1.second.from_now == 1.seconds.from_now
=> false
They look the same to me
irb(main):003:0> p 1.second.from_now; p 1.seconds.from_now; nil
2013-06-14 17:50:28 +0530
2013-06-14 17:50:28 +0530
=> nil
And they both have the same class
irb(main):004:0> 1.second.from_now.class == 1.seconds.from_now.class
=> true
Time elapses between both calls, that's why they are different:
Time.now == Time.now
#=> false
Time#to_f reveals that they are fractions apart:
a, b = 1.second.from_now, 1.second.from_now
a.to_f #=> 1371213500.506212
b.to_f #=> 1371213500.5062568
The call to second / seconds is identical:
1.second == 1.seconds
#=> true
1.second is an alias for 1.seconds, just to make your code more readable I guess. You can see it in the Numeric class in the Rails source.
Ok, this is my second attempt at debugging the memory issues with my Sinatra app. I believe I have it nailed down into simple sample code this time.
It seems when I filter an array through .map(&:some_method), it causes the items in that array to not get garbage collected. Running the equivalent .map{|x| x.some_method} is totally fine.
Demonstration: Given a simple sample class:
class C
def foo
"foo"
end
end
If I run the following in IRB, it gets collected normally:
ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
=> [...]
ruby-1.9.2-p180 :002 > b = a.map{|x| x.foo}
=> ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
=> 10
ruby-1.9.2-p180 :004 > a = nil
=> nil
ruby-1.9.2-p180 :005 > b = nil
=> nil
ruby-1.9.2-p180 :006 > GC.start
=> nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
=> 0
So no references to C exist anymore. Good. But substituting map{|x| x.foo} with map(&:foo) (which is advertised as equivalent), it doesn't get collected:
ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
=> [...]
ruby-1.9.2-p180 :002 > b = a.map(&:foo)
=> ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
=> 10
ruby-1.9.2-p180 :004 > a = nil
=> nil
ruby-1.9.2-p180 :005 > b = nil
=> nil
ruby-1.9.2-p180 :006 > GC.start
=> nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
=> 10
ruby-1.9.2-p180 :008 >
Is this a ruby bug? I'll try in more versions of ruby to be sure but this seems like an obvious issue. Anyone know what I'm doing wrong?
Edit:
I've tried this in 1.8.7-p352 and it doesn't have the issue. 1.9.3-preview1 does however still have the issue. Is a bug report in order or am I doing something wrong?
Edit2: formatting (why does putting four spaces before each line produce syntax highlighting while <pre> tags don't?)
As a.map(&:foo) should be the exact equivalent to a.map{|x| x.foo}, it seems like you really hit a bug in the Ruby code here. It cannot hurt to file a bug report on (http://redmine.ruby-lang.org/), the worst that can happen is that its being ignored. You can decrease the chances of that by providing a patch for the issue.
EDIT: I threw on my IRB and tried your code. I can reproduce the issue you describe on ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]. However, explicitely calling to_proc on the symbol does not suffer from the same problem:
irb(main):001:0> class C; def foo; end; end
=> nil
irb(main):002:0> a = 10.times.map { C.new }
=> [...]
irb(main):004:0> b = a.map(&:foo.to_proc)
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
irb(main):005:0> ObjectSpace.each_object(C){}
=> 10
irb(main):006:0> a = b = nil
=> nil
irb(main):007:0> GC.start
=> nil
irb(main):008:0> ObjectSpace.each_object(C){}
=> 0
It seems we are facing an issue with the implicit Symbol -> Proc conversion here. Maybe I will try to dive a bit into the Ruby source later. If so, I will keep you updated.
EDIT 2:
Simple workaround for the problem:
class Symbol
def to_proc
lambda { |x| x.send(self) }
end
end
class C
def foo; "foo"; end
end
a = 10.times.map { C.new }
b = a.map(&:foo)
p b
a = b = nil
GC.start
p ObjectSpace.each_object(C) {}
prints 0.
This question already has answers here:
Strange, unexpected behavior (disappearing/changing values) when using Hash default value, e.g. Hash.new([])
(4 answers)
Closed 7 years ago.
Code example below. Calling append on a hash value returns correctly but the hash itself doesn't behave as I would expect.
ruby-1.9.2-p290 :037 > r = {}
=> {}
ruby-1.9.2-p290 :038 > r.default = []
=> []
ruby-1.9.2-p290 :039 > r["c"] << 1
=> [1]
ruby-1.9.2-p290 :040 > r["c"]
=> [1]
ruby-1.9.2-p290 :041 > r
=> {}
ruby-1.9.2-p290 :042 > r.empty?
=> true
from the doc on default=:
Sets the default value, the value returned for a key that does not
exist in the hash. It is not possible to set the default to a Proc
that will be executed on each key lookup.
So you can use this:
irb(main):037:0> h = Hash.new { |hash, key| hash[key] = [] }
=> {}
irb(main):038:0> h[1] << "2"
=> ["2"]
irb(main):039:0> h
=> {1=>["2"]}
also you can use default_proc:
irb(main):047:0> h = {}
irb(main):047:0> h.default_proc = proc {|hash, key| hash[key] = []}
=> #<Proc:0x23939a0#(irb):47>
irb(main):049:0> h[1] << 3
=> [3]
irb(main):050:0> h
=> {1=>[3]}
It seems ruby hash uses r.default as default value for any r[<unassigned-key>]. So a single value is changed even if you specify different un-assigned keys. Please see below:
irb(main):001:0> r = {}
=> {}
irb(main):002:0> r.default = []
=> []
irb(main):003:0> r["c"] << 1
=> [1]
irb(main):004:0> r["c"]
=> [1]
irb(main):005:0> r["b"] << 2
=> [1, 2]
irb(main):006:0> r["b"]
=> [1, 2]
irb(main):007:0> r["c"]
=> [1, 2]
irb(main):010:0> r.default
=> [1, 2]
irb(main):008:0> r
=> {}
irb(main):009:0> r.empty?
=> true
Are Strings mutable in Ruby? According to the documentation doing
str = "hello"
str = str + " world"
creates a new string object with the value "hello world" but when we do
str = "hello"
str << " world"
It does not mention that it creates a new object, so does it mutate the str object, which will now have the value "hello world"?
Yes, << mutates the same object, and + creates a new one. Demonstration:
irb(main):011:0> str = "hello"
=> "hello"
irb(main):012:0> str.object_id
=> 22269036
irb(main):013:0> str << " world"
=> "hello world"
irb(main):014:0> str.object_id
=> 22269036
irb(main):015:0> str = str + " world"
=> "hello world world"
irb(main):016:0> str.object_id
=> 21462360
irb(main):017:0>
Just to complement, one implication of this mutability is seem below:
ruby-1.9.2-p0 :001 > str = "foo"
=> "foo"
ruby-1.9.2-p0 :002 > ref = str
=> "foo"
ruby-1.9.2-p0 :003 > str = str + "bar"
=> "foobar"
ruby-1.9.2-p0 :004 > str
=> "foobar"
ruby-1.9.2-p0 :005 > ref
=> "foo"
and
ruby-1.9.2-p0 :001 > str = "foo"
=> "foo"
ruby-1.9.2-p0 :002 > ref = str
=> "foo"
ruby-1.9.2-p0 :003 > str << "bar"
=> "foobar"
ruby-1.9.2-p0 :004 > str
=> "foobar"
ruby-1.9.2-p0 :005 > ref
=> "foobar"
So, you should choose wisely the methods you use with strings in order to avoid unexpected behavior.
Also, if you want something immutable and unique throughout your application you should go with symbols:
ruby-1.9.2-p0 :001 > "foo" == "foo"
=> true
ruby-1.9.2-p0 :002 > "foo".object_id == "foo".object_id
=> false
ruby-1.9.2-p0 :003 > :foo == :foo
=> true
ruby-1.9.2-p0 :004 > :foo.object_id == :foo.object_id
=> true
While above answers are perfect, Just adding this answer for future readers.
In most languages, string literals are also immutable, just like
numbers and symbols. In Ruby versions that are less than 3, all
strings are mutable by default. This changed in Ruby 3. Now all string
literals are immutable by default in Ruby 3++ versions.
On the last two lines:
$ ruby -v
ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10]
$ irb
irb(main):001:0> def t(str)
irb(main):002:1> str.index str
irb(main):003:1> end
=> nil
irb(main):004:0> t 'abc'
=> 0
irb(main):005:0> t "\x01\x11\xfe"
=> nil
irb(main):006:0> t "\x01\x11\xfe".force_encoding(Encoding::UTF_8)
=> nil
Why does str.index str return nil?
"\x01\x11\xfe" is not valid UTF8.
If you call t "\x01\x11\xfe".force_encoding(Encoding::BINARY), you'll get the expected 0.
The behavior is different on my older Ruby:
$ ruby -v ; irb
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
irb(main):001:0> def t(str)
irb(main):002:1> str.index str
irb(main):003:1> end
=> nil
irb(main):004:0> t 'abc'
=> 0
irb(main):005:0> t "\x01\x11\xfe"
=> 0
I suspect it has something to do with the difference between single-quotes and double-quotes with string literals in ruby:
ruby-1.9.1-p378 > def t(str) ; str.index(str) ; end
=> nil
ruby-1.9.1-p378 > t 'abc'
=> 0
ruby-1.9.1-p378 > t "\x01\x11\xfe"
=> nil
ruby-1.9.1-p378 > t '\x01\x11\xfe'
=> 0
The short answer is that using single-quotes does minimal text processing, but double-quotes allows interpolation, character escaping, and a few other things.
Some examples:
#interpolation
ruby-1.9.1-p378 > x = 5 ; 'number: #{x}'
=> "number: \#{x}"
ruby-1.9.1-p378 > x = 5 ; "number: #{x}"
=> "number: 5"
#character escaping
ruby-1.9.1-p378 > puts 'tab\tseparated'
tab\tseparated
=> nil
ruby-1.9.1-p378 > puts "tab\tseparated"
tab separated
=> nil
#hex characters
ruby-1.9.1-p378 > puts '\x01\x11\xfe'
\x01\x11\xfe
=> nil
ruby-1.9.1-p378 > puts "\x01\x11\xfe"
�
=> nil
I'm sure someone can explain better why this happens, this is just what I've experienced in my rubying.