Method explanation

Hello,

This is a beginner question, am going through a book where it gives an
example to show encapsulation, however, within the example itself it
uses concepts that it hasn’t previously explained properly, leaving me
somewhat confused.

I was hoping someone could possibly explain what’s going on. Here’s the
code example;


class Person
def initialize(age)
@age = age
end

def age
@age
end

def age_difference_with(other_person)
(self.age - other_person.age).abs
end

protected :age
end

fred = Person.new(34)
chris = Person.new(25)
puts chris.age_difference_with(fred)


The part that I don’t understand is “puts
chris.age_difference_with(fred)”. I realise that Chris/fred are both
object instances who have a set age. I understand the (fred) parameter,
as that correlates to the object parameter in the age_difference_with
method (other_person).

It’s the “chris.” part that I really don’t get. How does “self.age” in
the method correlate with the “chris.”? (I don’t fully understand
“self” part either. All I know is that it can be renamed and is used as
a method name ie.

“def self.count
@@count_object_instances
end”

and it is considered a class method)

Thanks for any explanation.

The “self” keyword is one of the great things about Ruby :slight_smile:
It can mean different things in different context.

When you write “self” inside an instance method, you’re referring to the
current instance. So “self.age” is referring to the age of chris or
fred; whoever called the method.

When you use “self.method” to define a method, “self” refers to the
Class. This means that the method is a “Class method”, which belongs to
the Class blueprint, and is independent of instances.

What “chris.age” is pointing to is this:

def age
@age
end

Because that method doesn’t start with “self.” (or one of the other ways
of defining class methods), it is an “instance method”, so it belongs to
that instance of the class: “chris”.

This can probably explain it better than I can:
Self in Ruby | Jimmy Cuadra (top Google result for
ruby self)

Here’s a quick demo of what notation is calling what method:

irb(main):001:0> class Person
irb(main):002:1> def age
irb(main):003:2> 1
irb(main):004:2> end
irb(main):005:1> def self.age
irb(main):006:2> 2
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> a = Person.new
=> #Person:0x2dd0e78
irb(main):010:0> a.age
=> 1
irb(main):011:0> Person.age
=> 2

On Sun, Jan 12, 2014 at 9:05 PM, Raja gopalan [email protected]
wrote:

method.So it’s an instance method to your class name. For an example,

class Raj
def self.hi
puts ‘hi’
end
end

Now I can access this method as Raj.hi it’s because Raj is an object of
class Class and this hi method is defined inside class Class.

class Raj
def self.hi
“#{caller.first}: hi”
end
end

puts Raj.hi
raj = Raj.new
puts raj.hi

these things are not the same.

hi Joel P.

you said:When you use “self.method” to define a method, “self” refers to
the
Class. This means that the method is a “Class method”, which belongs to
the Class blueprint, and is independent of instances.

I don’t think it’s completely independent of instances, because there is
not much difference between instance method and class method expect it’s
defined inside class Class. Your class name will act as object to that
method.So it’s an instance method to your class name. For an example,

class Raj
def self.hi
puts ‘hi’
end
end

Now I can access this method as Raj.hi it’s because Raj is an object of
class Class and this hi method is defined inside class Class.

hi tamouse m

I am saying Raj is the object of class Class, So you are directly
accessing like Raj.hi and

raj = Raj.new
puts raj.hi

You can’t access like this because hi is not in Raj class but it’s in
the class Class,So Raj is the object to access class Class.

I know “def self.hi” and “def hi” both are not same, but both functions
are defined in different class so we are using different object to
access that.

I feel I should add a little here. I’ll do it illustratively using code
examples, hopefully people can understand the underlying message.

  1. Define a method in a class, create an instance, and call the method
    on the instance.

class Foo
# Define a method
# Inside that method, ‘self’ refers to the instance object.
def asd
p self
end
end
my_foo = Foo.new
my_foo.asd #=> “#Foo:0x007fec18284568

We can’t do things like Foo.asd, because we haven’t added a class
method to Foo.

  1. A couple of ways of defining class methods:

Open the class ‘Foo’

Inside the class definition (but not inside methods),

‘self’ refers to the class object.

class Foo
# Define a class method
# Inside it, ‘self’ refers to the class object.
def self.asd
p self
end
end
Foo.asd #=> “Foo”

Like above, but we don’t rely on the word ‘self’

to refer to the class object.

class Bar
def Bar.asd
p self
end
end
Bar.asd #=> “Bar”

Like above, but doing things in different scopes.

class Baz
end
def Baz.asd
p self
end
Baz.asd #=> “Baz”

…etc. Note that you can use ‘def obj.meth’ to arbitrarily define
methods directly on the ‘obj’ (whether or not obj is called ‘self’ or
not).

What this actually does is define the method on obj’s singleton class,
which you can think of as a magic class that has exactly one instance:
obj

It might help, at this point, to remember a couple of things:

  1. class Foo; end opens (or reopens) the definition of class Foo
  2. the word ‘Foo’ in your code is a constant, and the value of that
    constant is an object, and that object is_a? Class
  3. this also works: Foo = Class.new

So ‘Foo’ is just another object, and when you call ‘Foo.blah’ ruby
searches:

  1. Foo.singleton_class, for any methods defined directly on Foo, like
    #asd
  2. Foo’s class, Class, for any instance methods defined there, like
    #ancestors
  3. … and on up the inheritance tree, through Module, Object, Kernel,
    etc.

It is possible to open (or reopen) an object’s singleton class using a
special extension syntax:

qux = Object.new
class << qux
def asd
p self
end
end
qux.asd #=> "#Object:0x007fec182ffdd0

Note that this is essentially the same as def qux.asd, but we can do
other things between the ‘class <<’ and the ‘end’, e.g.:

class << qux
private :asd
attr_accessor :bob
end
qux.bob = 123
qux.bob #=> 123
qux.asd #=> NoMethodError: private method `asd’ called for
#<Object:0x007fec182ffdd0 @bob=123>

Now, combining this with the fact that a class is just another object,
we can do:

class Qux
class << self
def asd
p self
end
private :asd
attr_accessor :bob
end
end
Qux.bob = 123
Qux.bob #=> 123
Qux.asd #=> NoMethodError: private method `asd’ called for Qux:Class

Note that, unless we explicitly write the word ‘Class’ in the code, or
do some other horrible hackery, we’re never adding instance methods to
the Class class. You could do the following:

class Class
def banana
‘yes please’
end
end

… which would make the following all work:

Foo.banana #=> “yes please”
Bar.banana #=> “yes please”
Integer.banana #=> “yes please”
Class.banana #=> “yes please”

But that’s different from defining ‘self.meth’ inside a class
definition.

Hope that makes sense.

+1 for Matthew K…

Just to emphasize Matthew’s point

class BarClass
def my_normally_defined_on_BarClass_class
end

def self.my_defined_prepended_with_self
end
end

bar_object = BarClass.new

def bar_object.my_defined_prepended_with_the_object
end

As the “normal” “methods” of the bar_object are not

defined on the bar_object itself. But they are

defined as “instance methods” of its class,

that is the BarClass.

So it is the BarClass (as an object of the class Class).

To define methods of the BarClass, I don’t

define them on the BarClass itself, but on its class.

And what is the class of the BarClass (object)?

It’s Class (another object :wink: ).

class Class
def my_normally_defined_on_Class_class
end
end

BarClass.methods.grep /my/

=> [:my_defined_prepended_with_self,

:my_normally_defined_on_Class_class]

BarClass.singleton_methods.grep /my/

=> [:my_defined_prepended_with_self]

bar_object.methods.grep /my/

=> [:my_defined_prepended_with_the_object,

:my_normally_defined_on_BarClass_class]

bar_object.singleton_methods.grep /my/

=> [:my_defined_prepended_with_the_object]

And, Yehuda K.'s post from 2009 still lives!

It’s all about self! :slight_smile:

Best regards,
Abinoam Jr.