5

The class

class A

  private
  def foo
    puts :foo
  end

  public
  def bar
    puts :bar
  end

  private
  def zim
    puts :zim
  end

  protected
  def dib
    puts :dib
  end
end

instance of A

a = A.new

test

a.foo rescue puts :fail
a.bar rescue puts :fail
a.zim rescue puts :fail
a.dib rescue puts :fail
a.gaz rescue puts :fail

test output

fail
bar
fail
fail
fail

.send test

[:foo, :bar, :zim, :dib, :gaz].each { |m| a.send(m) rescue puts :fail }

.send output

foo
bar
zim
dib
fail

The question

The section labeled "Test Output" is the expected result. So why can I access private/protected method by simply Object#send?

Perhaps more important:

What is the difference between public/private/protected in Ruby? When to use each? Can someone provide real world examples for private and protected usage?

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
maček
  • 76,434
  • 37
  • 167
  • 198

1 Answers1

8

Technically: Because send doesn't do anything to check method visibility. (It would be more work to do so.)

Philosophically: Ruby is a very permissive language. You can already just open up a class and make any method you want public. The language designers implemented send in a way that allows it to override the restrictions normally imposed by private. Ruby 1.9 was originally going to have two variants, a private-respecting send and an unsafe variant called send!, but this was apparently dropped for backwards compatibility.

As for what private, protected and public mean:

  • public methods can be called by any sender
  • protected methods cannot be called outside of an instance of the method's class or an instance of a subclass
  • private methods cannot be called with an explicit receiver (with a couple of exceptions, such as setter methods, which always have to have an explicit receiver, and so can be called within the class that way)
Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 1
    This makes sense, thank you. Could you add some real-world examples for *appropriate* use of `protected` and `private`? :) – maček Mar 25 '10 at 20:53
  • 3
    Good answer. It may be worth pointing out that Ruby 1.9 introduces `Kernel#public_send` which will not call protected/private methods. It's available for Ruby 1.8 with the `backports` gem. – Marc-André Lafortune Mar 25 '10 at 21:09
  • @smotchkkiss, that sounds like a separate question altogether. – glenn jackman Mar 25 '10 at 21:55