Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby protected visibility calling from superclass

I have this little code that seems to contradict in some way Ruby's documentation:

The second visibility is protected. When calling a protected method the sender must be a subclass of the receiver or the receiver must be a subclass of the sender. Otherwise a NoMethodError will be raised.

class Test
  def publico(otro)
    otro.prot
  end  
end

class Hija < Test
  protected def prot; end
end

Test.new.publico(Hija.new)

I get the folowing output:

NoMethodError: protected method `prot' called for # publico

What am I missing? Apparently the option " the receiver must be a subclass of the sender" is not available.

like image 484
Rodrigo Avatar asked Jul 30 '15 15:07

Rodrigo


2 Answers

Although it does not work on Parent Class which know nothing of the protected method, it works on the Subclasses of Subclass which define the protected method. Eg.

class A
  def n(other)
    other.m
  end
end

class B < A
  def m
    1
  end

  protected :m

end

class C < B
end

class D < C
end

a = A.new
b = B.new
c = C.new
d = C.new

c.n b #=> 1 -- sender C is a subclass of B
b.n b #=> 1 -- m called on defining class
a.n b # raises NoMethodError although reciever B is  a subclass of sender A
b.n c #=> 1 -- reciever C is subclass of sender B
c.n d #=> 1 -- reciever D is sublcass of sender C

We can probably conclude that the behaviour is something like " either the sender or the reciever must have inherited the method". With that behivaour, we can explain that since neither A (which does not know the existence of m) nor B (which knows the existence but not inherited it) ineherited the method, it raises the error.

Although there is also a possibility that this could be a bug.

like image 178
dreamingblackcat Avatar answered Nov 13 '22 07:11

dreamingblackcat


Protected methods can only be called from instances of the same class or a subclass. Hija is a subclass of Test. Test is not a subclass of Hija. So a protected method in Hija is not available to instances of Test.

So if your example were the other way:

class Hija
  protected def prot; end
end
class Test < Hija
  def publico(otro)
    otro.prot
  end
end
Test.new.publico(Hija.new)

works fine.

like image 40
Rich Niles Avatar answered Nov 13 '22 05:11

Rich Niles