Ruby: Why i cant define singlteon method on fixnum class - ruby

I want to define singleton method to every integer value (object) . but i am getting error while applying singleton method.
RubyDoc says There is effectively only one Fixnum object instance for any given integer value . what does this mean ?? how it is different from other normal classes?? i am not able to interpret this line.

I want to define singleton method to every integer value (object)
This is contradictory. The singleton class is for when you want something to apply to a single object. You want to define something for every integer object, so the singleton class is not an appropriate tool. Just use the normal class
class Integer
def foobar
"hey"
end
end
3.foobar
# "hey"
If you could modify the singleton class of 3, then there would be some behaviors that only apply to the number 3 and no other number. There is no technical reason to prevent that, but trust me that it's a good thing that you can't.
There is effectively only one Fixnum object instance for any given integer value
This is talking about something else. Notice the difference:
x = []
y = []
x == y # true
x.object_id == y.object_id # false!
x = 3
y = 3
x == y # true
x.object_id == y.object_id # true!
x.object_id == 5.object_id # false
Unlike most other objects, equal fixnums are identical objects. 3 and 5 are two different instances of Fixnum, but it is impossible to have two different instances of Fixnum that are both 3. Every 3 is the same. Again, this is not a technical necessity but more of a convenience for how most programmers think about numerical data.

It means that whenever you access some Fixnum, such as the number 1, you’re always treating with the same “instance”, this is mostly an implementation detail which ruby uses to optimize numbers.

The Integer class is frozen by default:
1.frozen?
=> true
There only ever exists one instance of any Integer object. You don't have to do anything special to enable this. In other words, the optimization you are trying to apply is built into Ruby.

Related

The commutative property of multiplication in Ruby

In ruby, I was messing around in the irb and found two code samples that should work the same but don't
"a" * 4 #this is "aaaa"
4 * "a" #this is "String can't be coerced into a Fixnum"
Doesn't this violate the commutative property of multiplication?
It does violate the commutative property, but that's not necessarily a problem, as the commutative property applies to the complex complex numbers in math. The reason "a" * 4 is not commutative in Ruby, as in most programming languages, is because a given type defines how it handles operators. So you could override the * operator for the String and Fixnum class (but that's a VERY VERY bad idea in practice):
class String
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of String"
end
end
end
class Fixnum
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of Fixnum"
end
end
end
So if you were to call
"a" * 4
Then it would print "The method was called on an instance of String" because that is equivalent to "a".*(4)
But this:
4 * "a"
Would print "The method was called on an instance of Fixnum" because 4 * "a" is equivalent to 4.*("a")
Here is a good article on operator overloading in Ruby.
Interesting side note: the commutative property actually doesn't apply to all numbers in math, the Quaterions and the Octonions both are not commutative.
Edit
If you wanted to, you could make the * operator commutative (but that would be a bad idea). You could then define * to swap the callee and the argument like such:
class Fixnum
def *(other)
other * self
end
end
That way, when ever you have 4 * "a" it would actually do this: "a" * 4. This would still work even if String#* was later redefined. Monkey patching can often be useful, but in this case it's a terrible idea, I don't recommend doing this, it's just a cool proof of concept.
"a" * 4 # repeat 'a' 4 times
4 * "a" # multiply 4 times the string 'a'
It's not multiplication unless two numbers are involved.
In Ruby, everything is an object. "a" is an object of class String, whereas 4 is an object of class Fixnum. So even numbers are objects.
And objects can have methods.
4 has a method called * that takes a number as an argument and multiplies 4 by that number. This method doesn't accept a string as an argument; it will unsuccessfully try to coerce the string to a number. (That's what explains your error message.)
"a" has a completely different method called * that takes a number as an argument. This method repeats the string multiple times.
Therefore:
4.*(4) # =>16
"a".*(4) # => "aaaa"
Ruby also lets you use a more succinct syntax for the * methods:
4 * 4 # =>16
"a" * 4 # => "aaaa"
But it's just a different way of writing the same thing.
No, it's a combination of precedence an the fact that they are both objects. What you are effectively doing in the 2nd version is 4.*("a"). Calling method '*' with parameter "a" on the Fixnum instance with value 4. So the String "a" cannot be coerced.

Ruby function called via the dot

I want to call a function named my_format_number like:
num = 5.5
formated_num = num.my_format_number
How can I do that in Ruby? And what is the name of these types of functions?
what is the name of these types of functions?
In object oriented programming (independent of programming language), a function that is bound to an object (often through the object's class) is called a 'method'. Some Ruby documentation calls all functions 'methods', though. For the sake of distinction, I'll use 'method' only to mean bound functions and keep referring to functions in general as 'functions'.
A function not bound to an object is usually called a 'free function'.
The object to which a method is bound is called the method's 'receiver'.
How can I do that in Ruby?
In Ruby, methods are always instance methods: They are defined on the class, but act on instances of the class. (I.e., the receiver must be an instance.) Other than in C/C++ or Java, all values in Ruby are objects (instances of classes), so every value has a class.
Class? What class?
A class is the type of a value/object/instance. It determines (to some degree) the value's semantic, as well as the methods available on that value.
What is the class of 5.5? Let's find out:
(5.5).class()
# => Float
(The shorter 5.5.class would have worked, too, but is a bit harder to understand.)
Float is Ruby's built-in class for floating point numbers.
Modifying the Float class
Class definitions in Ruby can be split up and distributed. Each chunk will have effect after having been interpreted, additional to the chunks already in effect, which means you can modify classes at runtime. This is known as 'monkey patching' or 're-opening a class'.
Let's re-open the Float class and add the my_format_number method. I decided it shall return a string:
class Float
def my_format_number
return "The number is #{self} and #{self} is the number."
end
end
(The return in front of the string could be skipped, as Ruby functions implicitly return the last expression they evaluate.)
Now you can call your new method on all Float values:
num = 5.5
formatted_num = num.my_format_number()
puts(formatted_num)
# The number is 5.5 and 5.5 is the number.
We don't even need variables and can invoke the method directly on value literals:
puts 7.8.my_format_number
# The number is 7.8 and 7.8 is the number.
It won't work for all numbers, though:
100.my_format_number
# NoMethodError: undefined method `my_format_number' for 100:Fixnum
# from (irb):15
# from :0
That's because we defined the number of Float and 100 is (as the error message tells us) not a Float but a Fixnum (a special kind of Integer).
Modifying several related classes at once
You could of course now also define the function of Fixnum. But there are numbers that are neither Fixnums nor Floats. So it would make sense to have the function at some central place.
We could monkey patch Ruby's master class, Object. But that would allow
"foobar".my_format_number
to return "The number is foobar and foobar is the number.", which doesn't make sense, as foobar is not a number. I'd only want our method to format numbers.
Let's see how the classes of Fixnum are structured:
Fixnum.superclass()
# => Integer
Fixnum.superclass().superclass() # equivalent to `Integer.superclass`
# => Numeric
Fixnum.superclass().superclass().superclass() # equivalent to `Numeric.superclass`
# => Object
The superclass method only gives us one direct ancestor. Using Ruby modules, multiple inheritance is possible, thus we can get some more results like so:
Fixnum.ancestors
# => [Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]
Let's see what the overlap is with
Float.ancestors()
# => [Float, Precision, Numeric, Comparable, Object, Kernel]
Comparable is probably more general than just numbers, while Precision might be too specific or even somewhat unrelated. (It's probably a module.) Let's modify Numeric thus, which (guessing from it's name) sounds like the right level of abstraction. Indeed, the documentation calls it
The top-level number class.
Therefore, very similar to before,
class Numeric
def my_format_number
return "The number is #{self} and #{self} is the number."
end
end
And now
100.my_format_number
# => "The number is 100 and 100 is the number."
If you want to know all the classes to which we've added the method in this second monkey-patching, have a look at Look up all descendants of a class in Ruby.
class Float
def my_format_number
...
end
end
I thought I'd add a simple example that demonstrates how to make and call a method using the .
def plus_two
self + 2
end
2.plus_two
=> 4

Ruby "CONSTANTS" seem to be INVISIBLY ALTERABLE?

I understand that "constants" in Ruby are by convention called constants but are in fact mutable. However I was under the impression that when they were "mutated" that there was a warning:
class Z2
M = [0,1]
end
Z2::M # => [0, 1]
Z2::M = [0,3]
(irb):warning: already initialized constant Z2::M
(irb):warning: previous definition of M was here
However I found this is not the case all the time:
a = Z2::M
a[1] = 2
Z2::M # => [0,2] and no warning
Is this a gap in the "warning" system? I am inferring that assignment of a constant would duplicate it, but I guess that is not true either as it appears that constants and variables point to the same object? Does this mean that all so-called "constants" need to be frozen in order to prevent them from being changed without warning?
TL;DR
Short of monkey-patching Kernel#warn (see https://stackoverflow.com/a/662436/1301972) to raise an exception, you won't be able to prevent reassignment to the constant itself. This is generally not a pragmatic concern in idiomatic Ruby code where one expects to be able to do things like reopen classes, even though class names are also constants.
A Ruby constant isn't actually immutable, and you can't freeze a variable. However, you can get an exception to be raised when something attempts to modify the contents of a frozen object referenced by the constant.
Freezing Objects Deeply with Plain Ruby
Freezing an Array is easy:
CONSTANT_ONE = %w[one two three].freeze
but the strings stored in this Array are really references to String objects. So, while you can't modify this Array, you can still (for example) modify the String object referenced by index 0. To solve this problem, you need to freeze not just the Array, but the objects it holds, too. For example:
CONSTANT = %w[one two three].map(&:freeze).freeze
CONSTANT[2] << 'four'
# RuntimeError: can't modify frozen String
CONSTANT << 'five'
# RuntimeError: can't modify frozen Array
Freezing Objects Recursively with a Gem
Since freezing recursive references can be a bit unwieldy, it's good to know there's a gem for that. You can use ice_nine to deep-freeze most objects:
require 'ice_nine'
require 'ice_nine/core_ext/object'
OTHER_CONST = %w[a b c]
OTHER_CONST.deep_freeze
OTHER_CONST << 'd'
# RuntimeError: can't modify frozen Array
OTHER_CONST[2] = 'z'
# RuntimeError: can't modify frozen Array
A Better Way to Use Ruby Constants
Another option to consider is calling Object#dup when assigning the value of a constant to another variable, such as instance variables in your class initializers, in order to ensure you don't mutate your constant's references by accident. For example:
class Foo
CONSTANT = 'foo'
attr_accessor :variable
def initialize
#variable = CONSTANT.dup
end
end
foo = Foo.new
foo.variable << 'bar'
#=> "foobar"
Foo::CONSTANT
#=> "foo"
There is no gap, as you are not altering a constant. And the fact is that Ruby constants are just variables with extra warnings.
Constant, just as every variable, is merely a pointer to the object in memory. When you doM = [0,3] you are creating a new array and re-pointing constant to this new object, which triggers a warning.
However, when you run M[0] = 1 you are just modifying referenced object, but you do not change the constant, as it still points to the same object.
Important thing to realize here is that all classes in Ruby are just objects in memory, referenced with constants, so when you do:
class Z2
end
it is equivalent to (if Z2 is not defined or is not pointing onto a class object already):
Z2 = Class.new
Naturally class is a very dynamic object, as we keep adding methods to it and so on - we definitively don't want this to trigger any warnings.
If you do Z2::M[1] = 2 you won´t get the message either. I believe the lack of warning occours because you are changing the Array itself and not the reference Z2::M.
If M was an integer, for exemple:
class Z2
M = 1
end
a = Z2::M
a = 2
a # => 2
Z2::M # => 1
To modify an Array from a constant without modify the original you can do:
class Z2
M = [0,1]
end
a = Z2::M.dup
a[0] = 1
a # => [1,1]
Z2::M # => [0,1]

Distinguish between index of a decimal number and integer inside an array in Ruby?

Since Ruby does type conversion, how do I get the index correctly?
I would like this to return 1
[1,2.0,2,3].index(2.0)
#=> 1
I would like this to return 2
[1,2.0,2,3].index(2)
#=> 1
Using a block together with eql? is one way:
[1,2.0,2,3].index {|e| e.eql? 2.0}
#=> 1
[1,2.0,2,3].index {|e| e.eql? 2}
#=> 2
Unlike ==, eql? returns true only if the receiver and the argument have the same type and equal values. So 2 == 2.0 returns true while 2.eql? 2.0 returns false.
Array#index and Equality
You aren't getting the results you expect because Array#index uses the more-generic BasicObject#== instead of Object#eql? to compare values, which doesn't take the type of the argument/value into account. In a duck-typing language, this is usually what you want.
Consider the following example, which uses == to compare a Float to a Fixnum:
2 == 2.0
#=> true
Note that Ruby considers the two numeric values to be equal, despite being of different types. This is documented behavior. Since the non-block form of Array#index returns the first index where the argument is == to the indexed value, [1,2.0,2,3].index(2.0) and [1,2.0,2,3].index(2) will both return the same index.
Use Block Form of Array#index
All Ruby methods accept an optional block, and some core classes behave differently when Kernel#block_given? is true. The documentation for Array#index says:
If a block is given...returns the index of the first object for which the block returns true. Returns nil if no match is found.
The canonical way to differentiate between two different types of values would use the block-form of Array#index to check for object equality with #eql? rather than with #==. For example:
array = [1,2.0,2,3]
array.index { |i| i.eql? 2 }
array.index { |i| i.eql? 2.0 }
This returns the values you'd expect, at the cost of a little extra typing. This is really the preferred solution to your problem.
Monkey-Patch the Array Class
Monkey-patching a core class like Array is generally a Bad Idea™, but you can force Array#index to behave the way you want by re-opening the Array class and modifying the behavior of Array#index to check for both type and value equality. One way to do this is with the help of Module#alias_method, and by using the block syntax of Array#old_index to check Numeric#eql? whenever you call Array#index with a numeric argument.
Consider the following:
class Array
alias_method :old_index, :index
def index value
old_index { |i| i.eql? value }
end
end
[1,2.0,2,3].index 2.0
#=> 1
[1,2.0,2,3].index 2
#=> 2
This works the way you seem to expect, and you can still use Array#old_index anytime you want the original type-agnostic equality check. However, use with care, as other modules or gems might not behave as expected once you've changed the normal behavior of the Array class.
It's nice to know you can do this, but juggling with chainsaws is an inherently risky activity. Your mileage may vary.

In Ruby, how does coerce() actually work?

It is said that when we have a class Point and knows how to perform point * 3 like the following:
class Point
def initialize(x,y)
#x, #y = x, y
end
def *(c)
Point.new(#x * c, #y * c)
end
end
point = Point.new(1,2)
p point
p point * 3
Output:
#<Point:0x336094 #x=1, #y=2>
#<Point:0x335fa4 #x=3, #y=6>
but then,
3 * point
is not understood:
Point can't be coerced into Fixnum (TypeError)
So we need to further define an instance method coerce:
class Point
def coerce(something)
[self, something]
end
end
p 3 * point
Output:
#<Point:0x3c45a88 #x=3, #y=6>
So it is said that 3 * point is the same as 3.*(point). That is, the instance method * takes an argument point and invoke on the object 3.
Now, since this method * doesn't know how to multiply a point, so
point.coerce(3)
will be called, and get back an array:
[point, 3]
and then * is once again applied to it, is that true?
Now, this is understood and we now have a new Point object, as performed by the instance method * of the Point class.
The question is:
Who invokes point.coerce(3)? Is it Ruby automatically, or is it some code inside of * method of Fixnum by catching an exception? Or is it by case statement that when it doesn't know one of the known types, then call coerce?
Does coerce always need to return an array of 2 elements? Can it be no array? Or can it be an array of 3 elements?
And is the rule that, the original operator (or method) * will then be invoked on element 0, with the argument of element 1? (Element 0 and element 1 are the two elements in that array returned by coerce.) Who does it? Is it done by Ruby or is it done by code in Fixnum? If it is done by code in Fixnum, then it is a "convention" that everybody follows when doing a coercion?
So could it be the code in * of Fixnum doing something like this:
class Fixnum
def *(something)
if (something.is_a? ...)
else if ... # other type / class
else if ... # other type / class
else
# it is not a type / class I know
array = something.coerce(self)
return array[0].*(array[1]) # or just return array[0] * array[1]
end
end
end
So it is really hard to add something to Fixnum's instance method coerce? It already has a lot of code in it and we can't just add a few lines to enhance it (but will we ever want to?)
The coerce in the Point class is quite generic and it works with * or + because they are transitive. What if it is not transitive, such as if we define Point minus Fixnum to be:
point = Point.new(100,100)
point - 20 #=> (80,80)
20 - point #=> (-80,-80)
Short answer: check out how Matrix is doing it.
The idea is that coerce returns [equivalent_something, equivalent_self], where equivalent_something is an object basically equivalent to something but that knows how to do operations on your Point class. In the Matrix lib, we construct a Matrix::Scalar from any Numeric object, and that class knows how to perform operations on Matrix and Vector.
To address your points:
Yes, it is Ruby directly (check calls to rb_num_coerce_bin in the source), although your own types should do too if you want your code to be extensible by others. For example if your Point#* is passed an argument it doesn't recognize, you would ask that argument to coerce itself to a Point by calling arg.coerce(self).
Yes, it has to be an Array of 2 elements, such that b_equiv, a_equiv = a.coerce(b)
Yes. Ruby does it for builtin types, and you should too on your own custom types if you want to be extensible:
def *(arg)
if (arg is not recognized)
self_equiv, arg_equiv = arg.coerce(self)
self_equiv * arg_equiv
end
end
The idea is that you shouldn't modify Fixnum#*. If it doesn't know what to do, for example because the argument is a Point, then it will ask you by calling Point#coerce.
Transitivity (or actually commutativity) is not necessary, because the operator is always called in the right order. It's only the call to coerce which temporarily reverts the received and the argument. There is no builtin mechanism that insures commutativity of operators like +, ==, etc...
If someone can come up with a terse, precise and clear description to improve the official documentation, leave a comment!
I find myself often writing code along this pattern when dealing with commutativity:
class Foo
def initiate(some_state)
#...
end
def /(n)
# code that handles Foo/n
end
def *(n)
# code that handles Foo * n
end
def coerce(n)
[ReverseFoo.new(some_state),n]
end
end
class ReverseFoo < Foo
def /(n)
# code that handles n/Foo
end
# * commutes, and can be inherited from Foo
end

Resources