Private vs. protected question

From a book I'm reading:

···

------------------------------------------------------------------------
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)
puts chris.age
-------------------------------------------------------------------------
results in:

9
:20: protected method 'age' called for #<Person:0x1e5f28 @age=25>
(NoMethodError)
------------------------------------------------------------------------
The first 'puts' line printed '9' on the screen, while the second
resulted
in error. This is because, like 'private', I cannot use a specific
receiver to call a protected method, correct?

Now I'm going to replace 'protected' with 'private' (and omit the last
line (puts chris.age) ). This would result in:

-------------------------------------------------------------------------
H:/Ruby/Practice/six.rb:9:in `age_difference_with': private method `age'
called for
#<Person:0x19ccf68 @age=25> (NoMethodError)from
H:/Ruby/Practice/six.rb:16:in `<main>'
------------------------------------------------------------------------

Explanation from the book:
" if
age were made private, the preceding example would fail because
other_person.age would
be invalid. That’s because private makes methods accessible only by
methods of a specific
object."

From the statement, "...because private makes methods accessible only by
methods of a specific
object.", I'm assuming that it also means 'accessible only by methods of
a single and CURRENT object', and that current object is 'chris', not
'fred', and that is why it resulted in error.

Am I wrong??
Help please! Thank you!!

--
Posted via http://www.ruby-forum.com/.

Kaye Ng wrote in post #991911:

Explanation from the book:
" if
age were made private, the preceding example would fail because
other_person.age would
be invalid. That’s because private makes methods accessible only by
methods of a specific
object."

From the statement, "...because private makes methods accessible only by
methods of a specific
object.", I'm assuming that it also means 'accessible only by methods of
a single and CURRENT object', and that current object is 'chris', not
'fred', and that is why it resulted in error.

Am I wrong??
Help please! Thank you!!

That explanation is about as clear as mud. The rule for private methods
is simple: you cannot call private methods with an explicit receiver.
Here is an example:

class Dog
  def bark
    puts 'woof'
  end
end

dog = Dog.new
dog.bark

--output:--
woof

In the last line, dog is the 'receiver'. If bark() is a private method,
you can't call it with a receiver, so that line would produce an error:

class Dog
  private
  def bark
    puts 'woof'
  end

end

dog = Dog.new
dog.bark

--output:--
prog.rb:10:in `<main>': private method `bark' called for
#<Dog:0xa1acde0> (NoMethodError)

The implications of the private method rule are a little bit tougher to
understand. How can you call bark() on an object if you are not allowed
to specify the object as the receiver? Well, in ruby if you call a
method without a receiver, then something called self becomes the
receiver by default--self is the implicit receiver.

Therefore, you must understand what object self is equal to in various
parts of your code:

puts self #main

class Dog
  puts self #Dog

  def bark
    puts self #<Dog:0x8e05c10>,
    puts 'woof'
  end

end

dog = Dog.new
puts dog #<Dog:0x8e05c10>

dog.bark #woof

ruby's notation for a dog object is the name of the class plus an id
number:

#<Dog:0x8e05c10>

Note what self is inside the bark method: it's the same object that
called the method(compare the id numbers), which is dog. That means
you can call private instance methods from inside public instance
methods:

class Dog
  def do_stuff
    bark
  end

  private
  def bark
    puts 'woof'
  end

end

dog = Dog.new
dog.do_stuff

--output:--
woof

The code works like this: dog calls do_stuff, so inside do_stuff self
is equal to dog. Because the private method bark() is called without a
receiver, the implicit receiver is self, which in this case is equal to
dog. And that is how you call a private method on an object like dog.

The protected method rule states that you can use a receiver to call the
method--so long as whatever object is self at that time is also an
object of the same class as the receiver.

···

--
Posted via http://www.ruby-forum.com/\.

In case all that was too confusing, to sum up:

private:
You can call private methods from inside public methods.

protected:
Protected methods act mostly like private methods, but in some cases you
are allowed to specify a receiver; those cases occur when self is equal
to a member of the same class as the receiver or a subclass of the
receiver.

···

--
Posted via http://www.ruby-forum.com/.

7stud -- wrote in post #991945:

The protected method rule states that you can use a receiver to call the
method--so long as whatever object is self at that time is also an
object of the same class as the receiver (or a parent or subclass).

I think we need to scratch '(or parent...' off the list:

class Animal
  def meth(obj)
    obj.bark #self=anim whose class is Animal,
  end #and Animal is a parent class of obj=dog
end

class Dog < Animal
  protected
  def bark
    puts 'woof'
  end
end

dog = Dog.new
anim = Animal.new
anim.meth(dog)

--output:--
prog.rb:3:in `meth': protected method `bark' called for #<Dog:0x9f8948c>
(NoMethodError)
  from prog.rb:22:in `<main>'

···

--
Posted via http://www.ruby-forum.com/\.