Is the frozen behavior on Fixnum a specified behavior? - ruby

Here was the behavior that somewhat surprised me:
1.9.3-p392 :001 > n = 1
=> 1
1.9.3-p392 :002 > n.frozen?
=> false
1.9.3-p392 :003 > 1.freeze
=> 1
1.9.3-p392 :004 > n.frozen?
=> true
I tried grepping through the RubySpec source code for frozen and I didn't see anything about Fixnums at all.
Is this behavior the same as what would be expected on non-MRI Ruby implementations? If I run n = 1; 1.freeze; n.frozen?, will the final result always be true on any Ruby implementation? Why or why not?

It looks like it is an intended feature. In Ruby Forum, a question is raised:
Isn't technically all Fixnums "frozen" (because you can't modify the state)?
to which matz answers:
Not really, since fixnums could have instance variables.
Thus, theoretically, there's room for freezing fixnums. I don't think it's worth the cost though.
There seems to have been unintended inconsistency between different MRI Ruby versions, but as far as MRI is concerned, they look like they were identified as bugs, and were fixed. The specification you observed seems to be the intended one.

Since everything in Ruby is an object, it perhaps shouldn't be surprising that you can freeze 1. Symbol has the same behavior. As mentioned in the comments, this behavior changed from 1.8.7 (freezing didn't do anything) to 1.9+ (freezing works).
What might be more surprising is that freezing 1 also freezes n. According to the documentation for Fixnum,
There is effectively only one Fixnum object instance for any given
integer value
This means that n and 1 are references to the same object, and modifying one will modify the other.
You can check this for yourself by looking at the object_id.
1.object_id
=> 3
n=1
n.object_id
=> 3
n.equal? 1
=> true
I tried this code in MRI 1.8.7, MRI 2.0.0, JRuby, and Rubinius and got the same result.

Related

What is Hash#count?

I was playing with IRB (Ruby 2.5.1) when I noticed this:
irb(main):020:0> h
=> {3=>4, :aaa=>false}
irb(main):021:0> h.count
=> 2
However, this method doesn't exist in Ruby docs.
A quick test shows that hsh.count gives the same result as hsh.keys.count, and Hash.ancestors contains Enumerable.
What exactly is Hash#count?
You seem to have gotten most of the way there... it's Enumerable#count.
Technically, hsh.keys.count is counting the keys, and hsh.count is counting the pairs (as would be yielded by hsh.each), but those are identical values in practice, because each pair has a unique key.

Why is .object_id in ruby sometimes returning positive or negative numbers?

I get this for a nil object in Ruby (irb):
nil.object_id # => 4
But for a string, I get negative results:
"abc".object_id # => -570954278
"abc".object_id # => -570956148
I am confused about the negative part. Is this proper or have I done something strange?
My ruby is:
ruby 2.3.0p0 (2015-12-25 revision 53290) [i686-linux]
The number effectively is a signed integer, with one bit used for sign and the rest used for data. See here for a discussion on some finer points of its implementation, mentioning the positive and negative storage.
But to be short, no, there isn't anything to worry about.

How to get nth root of a number in Ruby?

For example
x ** 3 # => 125
Knowing that the result of applying ** with an argument 3 to x is 125, how can I get the value of x?
Is there some kind of built-in method for this? I have been looking at the Math module but didn't find anything similar.
Using ** with 1/3:
125 ** (1.0/3)
# => 4.999999999999999
You could also try as below :
irb(main):005:0> 125**(3**-1)
=> 5
irb(main):006:0> 125**(3**-1.0)
=> 4.999999999999999
irb(main):007:0>
update
C:\Users >ruby -v
ruby 1.9.3p448 (2013-06-27) [i386-mingw32]
You can do an Nth root by raising to a fractional power. For example, the 4th root of 625 is 5.
(BigDecimal.new(625)**(1.0/4.0)).to_f
# => 5.0
Note, the .to_f is added for readability in this answer only. Don't cast it to a Float in your code unless you need to. IMHO, BigDecimals are "better" than Floats in Ruby - Floats lose precision too easily and you won't get accurate results. Case in point the accepted awnser above. The cube root of 125 is not 4.99999(repeat). It is 5.0 exactly.
Edit: the Ruby Class Rational seems to handle nth roots a little better.
2.3.3 :007 > 625.to_r ** 0.25
=> 5.0
But it still isn't as precise with a number that produces an irrational root.
2.3.3 :024 > (999.to_r ** 0.25) ** 4
=> 998.9999999999999
Close...but you should be able to get back to 999.0 exactly. My Mac's calculator and excel can do it. Main point - just be careful. If precision is important, Ruby may not handle this exactly the way one would expect.

Does seed generate same random sequence across different Rubys?

Suppose I call srand(1234), then call rand() repeatedly. Am I guaranteed to get the same sequence of random numbers regardless of my environment?
For instance,
Ruby 1.8.7 vs 1.9.3 vs 2.0
MRI vs JRuby
Windows vs Mac vs Linux
The answer in my experience is "yes"
I do this exact same thing when testing a new gem. The gem is not ready for real-world use, but relies heavily on random numbers, and most of the tests involve running Ruby's srand() beforehand so I get predictable numbers for assertions. All in all I probably test a few hundred small integers generated by rand() every time I run the test suite.
So far I have tested:
On Windows: MRI 1.9.3
On Mac: MRI 1.8.7, MRI 1.9.3 and MRI 2.0.0
On Travis (see build https://travis-ci.org/neilslater/games_dice), I test all these:
"1.8.7"
"1.9.3"
"2.0.0"
jruby-18mode # JRuby in 1.8 mode
jruby-19mode # JRuby in 1.9 mode
rbx-18mode
rbx-19mode
The last two of which I don't even know what they are :-)
The test suite has never failed due to an unexpected number from Ruby's rand method.
The underlying mechanism in Ruby is called the Mersenne Twister http://en.wikipedia.org/wiki/Mersenne_twister and this will generate same values from the same seeds, even across different languages, where it has been implemented. As far as I know, this algorithm is the one used by Ruby's rand() (and srand()) in all the standard implementations.
Well, this is what I get inside my irb - does it match what you get in yours? If so, then I think you can safely say "yes".
BTW, this is the whole point of seeding, so I expect the answer will definitely be "yes", and if not I'll be surprised.
ruby 1.9.3p327 (2012-11-10) [x86_64-darwin12.2.0]
irb(main):001:0> srand(1234)
=> 312936473923896776645464224839555650313
irb(main):002:0> rand
=> 0.1915194503788923
irb(main):003:0> rand
=> 0.6221087710398319
irb(main):004:0> rand
=> 0.4377277390071145
irb(main):006:0> rand
=> 0.7853585837137692
irb(main):007:0> rand
=> 0.7799758081188035

IRB - Ruby 1.9.x hash syntax: {if: true} is not equal to {:if => true}

Long story short, I was writing a method that included an options argument, that will do certain stuff if the value for the key :if, evaluated to true. When I trying the hash in IRB using the new syntax I got a syntax error in IRB, the prompt stays open:
1.9.3p374 :010 > {if: true}
1.9.3p374 :011?>
Using the old syntax, works just fine:
1.9.3p374 :011 > {:if => true}
=> {:if=>true}
All keywords that start a statement, exhibit the same behavior. E.g. def, do, module, case
Other reserved words that occur in the middle and class work just fine: else, end
My question is: Is this expected behavior, a bug or a limitation?
It's challenging to reliably and unambiguously parse things in any language. This is especially true when you start using reserved words. And irb has to go beyond that and provide an interactive model on top of the parser, which is even harder. I personally don't think there's too much value in worrying about cases like this, either as a user of the language or as a maintainer. In my mind, it's better to simply figure out what works and avoid getting into these situations if possible.
You can see some similar behaviors in plain Ruby, outside irb. For example:
puts({if: true}) # no problem, behaves as expected in Ruby 1.9.3.
puts {if: true} # raises a syntax error in Ruby 1.9.3
To answer your question, is it "expected behavior, a bug or a limitation", I'd say you should ignore irb and compare it to plain Ruby, and if you do this, it works fine. That means it has to be an irb bug.
But is it possible or worthwhile to solve? #coreyward makes a good point in his comment that irb has to delay execution in most cases when it encounters an if. You'd have to look further to know for sure, but you may not be able to unambiguously interpret all cases like this.
My advice: avoid this construct altogether if you can, and don't use reserved words for labels if you can avoid it!
Here's a file you can run with plain Ruby (eg MRI). You should see {:if=>true} in the output to confirm it works.
{if: true}
foo = {if: true}
# if MRI is working, should be able to execute this file without trouble.
p foo

Resources