Ruby function called via the dot - ruby

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

Related

Ruby: Why does `#hash` need to overridden whenever `#eql?` is overridden?

In this presentation the speaker has created a value class.
In implementing it, he overrides #eql? and says that in Java development, the idiom is that whenever you override #eql? you must override #hash.
class Weight
# ...
def hash
pounds.hash
end
def eql?(other)
self.class == other.class &&
self.pounds == other.pounds
end
alias :== eql?
end
Firstly, what is the #hash method? I can see it returns an integer.
> 1.hash
=> -3708808305943022538
> 2.hash
=> 1196896681607723080
> 1.hash
=> -3708808305943022538
Using pry I can see that an integer responds to #hash but I cannot see where it inherits the method from. It's not defined on Numeric or Object. If I knew what this method did, I would probably understand why it needs to be overridden at the same time as #eql?.
So, why does #hash need to be overridden whenever eql? is overridden?
Firstly, what is the #hash method? I can see it returns an integer.
The #hash method is supposed to return a hash of the receiver. (The name of the method is a bit of a giveaway).
Using pry I can see that an integer responds to #hash but I cannot see where it inherits the method from.
There are dozens of questions of the type "Where does this method come from" on [so], and the answer is always the same: the best way to know where a method comes from, is to simply ask it:
hash_method = 1.method(:hash)
hash_method.owner #=> Kernel
So, #hash is inherited from Kernel. Note however, that there is a bit of a peculiar relationship between Object and Kernel, in that some methods that are implemented in Kernel are documented in Object or vice versa. This probably has historic reasons, and is now an unfortunate fact of life in the Ruby community.
Unfortunately, for reasons I don't understand, the documentation for Object#hash was deleted in 2017 in a commit ironically titled "Add documents". It is, however, still available in Ruby 2.4 (bold emphasis mine):
hash → integer
Generates an Integer hash value for this object. This function must have the property that a.eql?(b) implies a.hash == b.hash.
The hash value is used along with eql? by the Hash class to determine if two objects reference the same hash key. […]
So, as you can see, there is a deep and important relationship between #eql? and #hash, and in fact the correct behavior of methods that use #eql? and #hash depends on the fact that this relationship is maintained.
So, we know that the method is called #hash and thus likely computes a hash. We know it is used together with eql?, and we know that it is used in particular by the Hash class.
What does it do, exactly? Well, we all know what a hash function is: it is a function that maps a larger, potentially infinite, input space into a smaller, finite, output space. In particular, in this case, the input space is the space of all Ruby objects, and the output space is the "fast integers" (i.e. the ones that used to be called Fixnum).
And we know how a hash table works: values are placed in buckets based on the hash of their keys, if I want to find a value, then I only need to compute the hash of the key (which is fast) and know which bucket I find the value in (in constant time), as opposed to e.g. an array of key-value-pairs, where I need to compare the key against every key in the array (linear search) to find the value.
However, there is a problem: Since the output space of a hash is smaller than the input space, there are different objects which have the same hash value and thus end up in the same bucket. Thus, when two objects have different hash values, I know for a fact that they are different, but if they have the same hash value, then they could still be different, and I need to compare them for equality to be sure – and that's where the relationship between hash and equality comes from. Also note that when many keys and up in the same bucket, I will again have to compare the search key against every key in the bucket (linear search) to find the value.
From all this we can conclude the following properties of the #hash method:
It must return an Integer.
Not only that, it must return a "fast integer" (equivalent to the old Fixnums).
It must return the same integer for two objects that are considered equal.
It may return the same integer for two objects that are considered unequal.
However, it only should do so with low probability. (Otherwise, a Hash may degenerate into a linked list with highly degraded performance.)
It also should be hard to construct objects that are unequal but have the same hash value deliberately. (Otherwise, an attacker can force a Hash to degenerate into a linked list as a form of Degradation-of-Service attack.)
The #hash method returns a numeric hash value for the receiving object:
:symbol.hash # => 2507
Ruby Hashes are an implementation of the hash map data structure, and they use the value returned by #hash to determine if the same key is being referenced.
Hashes leverage the #eql? method in conjunction with #hash values to determine equality.
Given that these two methods work together to provide Hashes with information about equality, if you override #eql?, you need to also override #hash to keep your object's behavior consistent with other Ruby objects.
If you do NOT override it, this happens:
class Weight
attr_accessor :pounds
def eql?(other)
self.class == other.class && self.pounds == other.pounds
end
alias :== eql?
end
w1 = Weight.new
w2 = Weight.new
w1.pounds = 10
w2.pounds = 10
w1 == w2 # => true, these two objects should now be considered equal
weights_map = Hash.new
weights_map[w1] = '10 pounds'
weights_map[w2] = '10 pounds'
weights_map # => {#<Weight:0x007f942d0462f8 #pounds=10>=>"10 pounds", #<Weight:0x007f942d03c3c0 #pounds=10>=>"10 pounds"}
If w1 and w2 are considered equal, there should only be one key value pair in the hash. However, the Hash class is calling #hash which we did NOT override.
To fix this and truly make w1 and w2 equals, we override #hash to:
class Weight
def hash
pounds.hash
end
end
weights_map = Hash.new
weights_map[w1] = '10 pounds'
weights_map[w2] = '10 pounds'
weights_map # => {#<Weight:0x007f942d0462f8 #pounds=10>=>"10 pounds"}
Now hash knows these objects are equal and therefore stores only one key-value pair

Ruby: Why i cant define singlteon method on fixnum class

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.

How do I use `:rand` as a unary method with map/collect?

I want a vector containing the result of rolling 10 dice (say). I can do this:
([6]*10).map{|x|rand(x)}
But this gives me a "wrong number of arguments" error:
([6]*10).map(:rand)
Is there a point-free way to pass the one-argument version of rand to map?
This will work:
([6]*10).map(&method(:rand))
This won't:
([6]*10).map(&:rand)
Symbol#to_proc is (roughly) implemented like this:
class Symbol
def to_proc
-> *args { args.first.public_send(self, *args.drop(1)) }
end
end
In other words, it takes the first argument as the receiver and the other arguments as arguments to the method that is named by the Symbol. So, in your case, it is calling
6.rand
over and over.
This "kind of" works, because 6 is an Integer, Integer is an indirect subclass of Object, which mixes in Kernel, which defines rand. But! rand is private, which means it can only be called without an explicit receiver. Also, you aren't passing any arguments, therefore even if it were public, you'd get the behavior of rand without arguments, which is a Float between 0 and 1.
Whereas Method#to_proc passes all arguments to the method (it already has its receiver bound, after all), so in this case, it will call
self.rand(6)
over and over. Which of course works, because self is an Object, Object includes Kernel, and rand is defined in Kernel.
This won't work as well:
([6]*10).map(:rand)
For the simple reason that map doesn't have any parameters, but you are passing an argument.
You can write:
([6]*10).map(&method(:rand))
This would be clean way to write it:
10.times.map { rand(6) }
Writing it this way makes it easier to see what argument is passed to rand.

Why ruby constants are changable? What is the difference between variable?

I was learning ruby, and i learnt that ruby constants must start with a Upper case letter (e.g. Myconstant). This will make it a constant, but its value is changeable!
If a constant's value is changeable then why do we need constant, what is the difference between variable then?
Constants have lexical scoping, whereas methods have dynamic scoping:
class Super
Constant = "Super::Constant"
def method
'Super#method'
end
def get_constant
Constant
end
def get_method
method
end
end
class Sub < Super
Constant = 'Sub::Constant'
def method
'Sub#method'
end
end
Super.new.get_constant # => "Super::Constant"
Sub.new.get_constant # => "Super::Constant"
Super.new.get_method # => "Super#method"
Sub.new.get_method # => "Sub#method"
And as far as variables, they are inaccessible from the outside. How would you intend to access these?
class Object
Constant = 'constant'
local_var = 'local var'
#instance_var = 'instance var'
##class_var = 'class var' # btw, never use these
end
Also, there's a lot of things you can do in Ruby, but for your own sanity, be wary. I'd recommend against changing constants around, it will likely frustrate your team.
Ruby lets you shoot yourself in the foot (if you really want to). But, at least in this case, it warns you about it.
ONE = 'one'
ONE = 'two' # !> already initialized constant ONE
Some reasons:
1) Convention. It's easy to see just from the name of an identifier that it's not supposed to change.
2) Technical. It (probably; someone more knowledgeable than I will probably answer) makes the interpreter simpler.
3) Dynamism is sometimes helpful; in testing, for example, it's possible to redefine things for testing purposes rather than having to stub/proxy everything…
I use this feature sometimes to test out code without otherwise necessary parameters, eg when i run the script from my editor where it is difficult to provide a parameter.
#ARGV[0] = "c:/test.txt" #in case of testing i remove the first remark sign

Is everything an object in ruby?

Is everything in ruby an object? Does this include Fixnums?
Depends on what you mean by "everything". Fixnums are, as the others have demonstrated. Classes also are, as instances of class Class. Methods, operators and blocks aren't, but can be wrapped by objects (Proc). Simple assignment is not, and can't. Statements like while also aren't and can't. Comments obviously also fall in the latter group.
Most things that actually matter, i.e. that you would wish to manipulate, are objects (or can be wrapped in objects).
Yes. Fixnum is a class, which inherits from Integer, which inherits from Numeric, which finally inherits from Object.
Or, why don't you just ask it? :)
1.is_a? Object # => true
1.class # => Fixnum
Fixnum.is_a? Object # => true
Reading the Ruby info and documentation on the website is a good idea too.
Practically everything in Ruby is an Object, with the exception of control structures. Whether or not under the covers a method, code block or operator is or isn't an Object, they are represented as Objects and can be thought of as such.
Take a code block for example:
def what_is(&block)
puts block.class
puts block.is_a? Object
end
> what_is {}
Proc
true
=> nil
Or for a Method:
class A
def i_am_method
"Call me sometime..."
end
end
> m = A.new.method(:i_am_method)
> m.class
Method
> m.is_a? Object
true
> m.call
"Call me sometime..."
And operators (like +, -, [], <<) are implemented as methods:
class String
def +
"I'm just a method!"
end
end
For people coming into programming for the first time, what this means in a practical sense is that all the rules that you can apply to one kind of Object can be extended to others. You can think of a String, Array, Class, File or any Class that you define as behaving in much the same way. This is one of the reasons why Ruby is easier to pick up and work with than some other languages.
Yes everything is an object in ruby, and that includes Fixnum
Ruby doen't have any primitives (like int, char etc in java), so every value (anything that can sit on the right of an assignment statement) is an object. However, control statements, methods, and other features of the language syntax aren't.
Yup.
> Fixnum.is_a?(Object) #=> true
To see the chain of inheritance:
> pp Fixnum.ancestors
[Fixnum,
Integer,
Precision,
Numeric,
Comparable,
Object,
...
Kernel]
=> nil

Resources