self vs class name for class methods in inheritance - ruby

In this code:
class Dog
def self.bark
print "woof"
end
end
class Little_dog < Dog
end
Little_dog.bark
the method is inherited from a generalised class that references self. But the next patch of code:
class Dog
def Dog.bark
print "woof"
end
end
class Little_dog < Dog
end
Little_dog.bark
also works. I was expecting it to give me an error, but it didn't.
How does self refer to the class method under class inheritance? Why does the little_dog class have a class method bark in the second example when I only defined it as a class method of Dog?

self is widely used in Ruby Metaprogramming.
From Metaprogramming Ruby book:
Every line of Ruby code is executed inside an object—the so–called
current object. The current object is also known as self, because
you can access it with the self keyword.
Only one object can take the role of self at a given time, but no
object holds that role for a long time. In particular, when you call a
method, the receiver becomes self. From that moment on, all instance
variables are instance variables of self, and all methods called
without an explicit receiver are called on self. As soon as your code
explicitly calls a method on some other object, that other object
becomes self.
So, in code:
class Dog
# self represents the class object i.e: Dog. Which is an instance of Class.
# `bark` will be treated as class method
def self.bark
print "woof"
end
end
can also be written as:
class Dog
# Dog is an instance of Class.
# `bark` will be treated as class method
def Dog.bark
print "woof"
end
end
Inheritance allows a subclass to use features of its parent class. That's why you can access bark method in Little_dog class since it is inherited Dog class:
class Little_dog < Dog
# has `bark` as a class method because of Dog
end
Ruby style guide tip: In Ruby it's considered as a best practice to use CamelCase convention for naming classes and modules.

When you're defining class method it actually doesn't matter if you use
Dog.bark
or
self.bark
Both method defines class method which will be inherited by subclasses.
Only difference is when you will be changing name of class Dog to something else, like BigDog - when you use Dog.bark it obviously needs to be changed to BigDog.bark.
When using self method definition, self.bark will still work.

Related

Why can some classes and/or methods be called without instances of their parent class?

I'm near the finish of the Ruby track in Code Academy, and I'm curious about a peculiar thing: I was under the impression that a class is a repository of constants, methods, etc... and that in order to access most of them, you would first need to create an instance of that class or in some cases the methods of themselves can be invoked (as in they are all technically part of the global object). And then I saw something like this:
#Worked
Time.now
I understood as this as the method [now] of instance of class [Time] being invoked. I then tried to invoke the method on its own:
#Failed
now
and that failed, and I assumed that while a method can be created in the general scope [as part of the global object], if it relies on initialized variables of "parent" class, it cannot be called on its own, because it would not know which object to search for those initialized variables. Following that I created a test class:
class Clock
def initialize
#hours = 1
#minutes = 30
end
def showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
#this worked
watch = Clock.new
watch.showTime
#this failed
showTime
I then just created a basic method (assuming it's in the global level)
def mymethod
puts "The mighty METHOD!"
end
#Works
mymethod
and calling this method the way I did, without referencing the global object worked. So... the questions I have are as follows:
How can [Time.now] be called in this fashion? Shouldn't there be an instance of Time first created?
Why can't I call the method [now] on its own? Am I right that it relies on resources that it cannot find when called this way?
Why could I not call the method showTime on its own? But if I define any method on the "global" level I can access it without referencing the global object
First of all, your intuition is correct.
Every methods must be an instance method of some receiver.
Global methods are defined as private instance methods on Object class and hence seem to be globally available. Why? From any context Object is always in the class hierarchy of self and hence private methods on Object are always callable without receiver.
def fuuuuuuuuuuun
end
Object.private_methods.include?(:fuuuuuuuuuuun)
# => true
Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class class and may have singleton methods.
class A
class << self # the singleton class
def example
end
end
end
A.singleton_class.instance_methods.include?(:example)
# => true
Alternative ways of defining class methods are
class A
def self.example
end
end
# or
def A.example
end
Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name) as follows
str = "hello"
def str.square_size
size * size
end
str.square_size
# => 25
"any other string".square_size
# => raises NoMethodError
Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on Enumerable) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again.
This is known as a class method. If CodeAcademy didn't cover it, that's a shame. Here's some examples:
# basic way
class Foo
def self.bar; :ok; end
end
Foo.bar # => :ok
# alternate syntax
class Foo
class << self
def bar; :ok; end
end
end
# alternate syntax, if Foo class already exists
def Foo.bar; :ok; end
# alternate approach if Foo class already exists
Foo.class_exec do
def bar; :ok; end
end
# to define a class method on an anonymous 'class' for a single instance
# you won't need to use this often
Foo.new.singleton_class.class_exec do
def bar; :ok; end
end
# to define a class method on an instance's actual class
Foo.new.class.class_exec do
def bar; :ok; end
end
Another way to get class methods is to extend a module.
module FooMethods
def bar; :ok; end
end
module Foo
extend FooMethods
end
Foo.bar # => :ok
Note that with Modules, the methods are always defined as instance methods. This way they can be either extended into class scope or included into instance scope. Modules can also have class methods, using the exact same syntax / examples as shown above with classes. However there's not such as easy to load a module's class methods via include or extend.
How can [Time.now] be called in this fashion? Shouldn't there be an
instance of Time first created?
The Time.now method is a class method, not an instance method and therefore can be called directly on the Time class rather than an instance of it Time.new
Class methods are defined on the class themselves using the self keyword:
class Time
def self.now
# code
end
end
Time.now # works
Why can't I call the method [now] on its own? Am I right that it
relies on resources that it cannot find when called this way?
When you call a method "on its own" you're actually implicitly calling it on self:
self.now
The above is the same as just doing:
now
Why could I not call the method showTime on its own? But if I define
any method on the "global" level I can access it without referencing
the global object
You defined the showTime method on a specific class so you have to send that method to that class. When you define a method in the "global" scope you're implicitly defining it on self and the subsequent call to mymethod is actually self.mymethod so it will work.
Time.now is a class method.
To define a class method, you need to define the method with self. : def self.method_name
class Clock
#hours = 1
#minutes = 30
def self.showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
Clock.showTime
#=> The time is: 1:30
If you want to call now on its own, you can do so inside Time class :
class Time
puts now
#=> 2017-01-19 22:17:29 +0100
end

Ruby: What is the difference between writing extend outside the class and inside the class

I have read this question at url In Ruby or Rails, why is "include" sometimes inside the class and sometimes outside the class?. As per the answer of this question i am expecting the method print2 of module Calculation should be accessible to the class Addition and ABc .but i am getting error as undefined methodprint2' for Addition:Class (NoMethodError)`
module Calculation
def print2
puts "print2"
end
end
require '/home/sanjay/Desktop/m'
extend Calculation;
class Addition
end
class Abc
end
Addition.print2
Abc.print2
Please explain why this error is comming??
Thanks
The receiver of extend should be each class, so you want Addition.extend Calculation and Abc.extend Calculation (after the class definitions). The semicolon is not required.
module D
def dog
puts "woof"
end
end
class A; end
A.extend D
A.dog #=> "woof"
class B; end
B.extend D
B.dog #=> "woof"
My hunch is that your extend (outside any class) extends the Eigenclass of main. Main being the instance of Object that is your current runtime environment. An Eigenclass is the class of an object whose only instance is the given object. Each object in Ruby has a Eigenclass. Nothing inherits from an Eigenclass. So your extend is not inherited to any other classes.

Ruby dynamically instantiate class

How to reference to a class within a static method?
class Car
def self.new_from_xml(xml)
instance = self.class.new
#do some stuff with xml
instance
end
end
class Mercedes < Car
end
class Porsche < Car
end
IRB:
Mercedes.new_from_xml(somedata) # Output is #<Class:...>, should be #<Mercedes:...>
Porsche.new_from_xml(somedata) # Output is #<Class:...>, should be #<Porsche:...>
Instead of
instance=self.class.new
just write
instance = new
Why is this?
Well, in first place, you have to understand that you are calling a class method, thus you are at a class level already. The .new method is a class method, so you can call it directly without calling self.class.new.
Why does self.class.new return Class?
Because the class of the class Car is Class (I know, sounds weird ;), because classes in Ruby are instances of Class.
This is actually a pretty deep concept, I recommend you read more about it. One nice reference I have read is the book Metaprogramming Ruby by Paolo Perrotta (ISBN-10: 1934356476) [1].
http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Pros/dp/1934356476
Since you are already in a class method, you should use self.new (or simply new, as #tokland wrote) instead of self.class.new:
class Car
def self.new_from_xml(xml)
instance = new
#do some stuff with xml
end
end
class Mercedes < Car
end
class Porsche < Car
end
p Mercedes.new_from_xml(nil) #=> #<Mercedes:0x007f042d0db208>
p Porsche.new_from_xml(nil) #=> #<Porsche:0x007f042d0db118>
From a comment to this answer: Why does self.class reference to class? What's the logic here?
Inside a class block self references the class you are editing:
class Car
puts self #=> writes Car
end
Using def self.new_from_xml it is like if you are declaring def Car.new_from_xml, that is a method of the Car object (which is an instance of Class); so inside new_from_xml self coincides with Car.

Top-level method can be accessed from another class in Ruby?

How is it possible that if I define a method in the Object class (which is defined as private), I am able to call it from inside another class? I mean, when I call say_hello from inside the class Dog, how is it resolved if say_hello is a top-level defined method and therefore is private to the Object class? I know the Object class is in the method lookup of all the classes, but if the method is private it should not be accessible right?
def say_hello
p "Hello"
end
class Dog
def test_hello
say_hello
end
end
prova = Dog.new
prova.test_hello
I guess an easier explanation of my doubt would be: Why can I call a private method of a parent from a child?
class Animal
private
def prova
p "hello"
end
end
class Dog < Animal
def test_hello
prova
end
end
prova = Dog.new
prova.test_hello
Remember Dog inherits from Object, giving it access to Objects methods. You can extend the Object class all you want.
See answer to: How to extend class Object in Rails?
but if the method is private it should not be accessible right?
What makes you think that?
Private methods can only be called with an implicit receiver. You are calling it with an implicit receiver. Ergo, it should work … and it does.

class methods syntax in ruby

the ruby book I'm reading has confused me a bit. If I do the following, I understand completely why the code throws an error;
class Person
def show_name
puts #name
end
end
person = Person.new
person.show_name
Person.show_name #(note the capital P) this line falls over
It throws an error stating that the Person class does not have a method called show_name, because it is an instance method. I understand this completely. The book then throws in this example;
class Class
def add_accessor(accessor_name)
self.class_eval %Q{attr_accessor :#{accessor_name}}
end
end
class Person
end
person = Person.new
Person.add_accessor :name #note the capital P
Person.add_accessor :age #capital P here too
person.name = "Mikey"
person.age = 30
puts person.name
and goes on to state how cool it is that you can add methods to classes dynamically. What I don't understand is why I am suddenly allowed to call the "add_accessor" method as a class method (with a capital P) when the method itself isn't defined as such? I thought all class methods had to be declared like this?
class Math
def self.PI
3.141
end
end
puts Math.PI
Is anyone able to enlighten me?
Ruby classes are objects like everything else to. Your Person class is really an object of class Class, which in turn inherits from class Module. When you add a method to class Class as an instance method, you are providing a new method for all classes.
If you had declared it with a def in Person, it would not be callable without an object. To add class methods for one class, but not all, you must prepend the method name with self or the name of the class:
class Person
def instance_method
end
def self.class_method
end
def Person.other_class_method
end
end
When you declare the method as self.class_method you are declaring your method to be a singleton method on the class object. self in a class or module declaration refers to the class object, which is why self. and Person. are the same.
When dealing with Ruby, just remember everything is an object, everything has methods. There are no functions in Ruby either, despite appearances to the contrary. Methods and objects, always.
Look at this:
person.instance_of?(Person) #=> true
Person.instance_of?(Class) #=> true
You have defined an instance method add_accessor for all the instances of the class Class, so Person class can use that method because it is an instance of Class.
I recommend yout to take a look at metaprogramming and Ruby Object Model.
Hoep this helps
You're extending the Class class, and all of your classes, like Person, are instances of Class (Yes, classes are instances of the Class class. They're ordinary objects).
So when you call Person.add_accessor, you're calling the instance method Class#add_accessor.
because Person (with capital P ) is an instance of the class Class.

Resources