#send and private methods

I apologize if this has been discussed before and I missed it...

What's the rationale for having #send bypass the private status of a method? For instance:

irb(main):001:0> b = Object.new
=> #<Object:0x2ae06d8>
irb(main):002:0> b.gets
NoMethodError: private method `gets' called for #<Object:0x2ae06d8>
        from (irb):2
irb(main):003:0> b.send("gets")
no!
=> "no!\n"
irb(main):004:0>

In my mind, #send should honor the visibility of a method and only allow calls to private methods if called like

self.send("gets")

But maybe there's a good reason for this behavior that I'm simply missing.

- Brian Palmer

What's the rationale for having #send bypass the private status of a method?

That it's endlessly useful to be able to mindfully sidestep the rules when the pressures are right. I use this to much delight in various places in Rails where I'm well aware of the fact that the call is to a private, but I choose to anyway.

To me, that's the essence of Ruby. Guidance, not constraints. Make it ugly instead of impossible.

Three cheers for a send that sidesteps visibility ;)!

···

--
David Heinemeier Hansson,
http://www.basecamphq.com/ -- Web-based Project Management
http://www.rubyonrails.org/ -- Web-application framework for Ruby
http://macromates.com/ -- TextMate: Code and markup editor (OS X)
http://www.loudthinking.com/ -- Broadcasting Brain

Brian Palmer wrote:

In my mind, #send should honor the visibility of a method and only allow calls to private methods if called like

self.send("gets")

But maybe there's a good reason for this behavior that I'm simply missing.

Off the top of my head:

Ruby is (almost) pure OO if that is what you want. And it behaves that way so long as you follow the OO conventions. And most Ruby developers do.

However, it provides numerous hooks and inlets such that you can pretty much do as you like; the proverbial enough rope to shoot yourself in the foot.

Why might this be? I would posit that programming languages exist to aid the developer, not the computer, and so should be enabling, not prohibitive.

OOP>A>D is/are a set of design and development guidelines, not the Ten Commandments, so a language should not dictate, merely encourage. (Maybe even strongly encourage.)

Any reasonably powerful language provides the wherewithal to write difficult, ugly, unreadable, unmaintainable, dangerous code. What stops most people from doing so is typically not the constraints of a language, but common sense and self-preservation.

Using something like 'send' on private methods is similar to off-road driving. You can deliberately choose to step outside the boundaries, but you have to be responsible for your actions.

Ruby treats you like an adult.

James

I find that my sympathies lie with the original poster (Brain Palmer) with
regard to Object#send bypassing conventional access controls, although I do
agree that the rationales presented by the other responders are more than
likely historically accurate.

What I mean is this. Private access designation, although an artifact of OO
methodology, serves a much broader role. It is a mechanism for allowing a
programmer to organize his or her implementation while explicitly noting
that certain details of the implementation are subject to change. It is
way of saying that such details should not be relied upon by clients of the
implementation. Why? To put it simply, it is a way of saying "these
things may behave differently or be entirely absent in future releases of
this component."

Although I agree that programming languages should be "enabling" in that
they should promote creative problem-solving and although I agree that
"adult" programmers accept the responsibility of bypassing the constraints
imposed upon them by the structure of the programming languages that they
use, the fact of the matter is that it is not necessarily the creative and
mature programmer who suffers the consequences of having taken such
liberties with access control. Sadly, other programmers - and ultimately
end users - who rely on the integrity of complex software systems to
continue to function properly in spite of ongoing revision are the ones
likely to be injured when access controls are disregarded.

In other words, information hiding is a way of making software systems
resilient in the face of change. It is not simply a way "nanny"
programming languages try to keep "top-gun" programmers from getting their
job done. Of course, for small projects with a restricted user base these
constraints hardly matter. If Ruby were intended to be only a prototyping
tool, then bypassing access controls would be no big deal. But Ruby
apparently is on the way to being adopted as a bona fide
progamming-language-in-the-large, as evidenced by such trailblazing
projects as the Rails framework. (I certainly hope so!) Consequently I
think that the adherence to a rigorous informtation hiding schema should be
taken seriously and mechanisms to bypass it should be brought into
question.

- Marc Merlin

I certainly see what you mean--I can think of cases where it would be useful to bypass the private status of a method, as well. I was curious how others felt, though. The reason I ran across the #send behavior is this--I've been toying with different ways of writing a Infocom-style text adventure interpreter in Ruby, and one idea I had was a 'command' object or module that would contain a bunch of methods named after verbs, such as 'look' and 'west'. Then I would just have the interpreter do a #send with whatever the user typed in, and let #method_missing handle the "I don't understand what you mean" type messages. I was just a bit shocked when I discovered that typing 'gets' into my interpreter actually called the private method 'gets' (and I started thinking about what the adventurous adventurer could do with a well-designed #instance_eval command :slight_smile:

But of course, this is easily avoided by checking whether #send would call a public method, or using the awesome "evil ruby" to make a class without Object and Kernel methods. Not to mention that, while an interesting idea, it's not necessarily the most elegant way to do things anyway.

Thanks for the feedback!

- Brian Palmer

David Heinemeier Hansson wrote:

···

What's the rationale for having #send bypass the private status of a method?

That it's endlessly useful to be able to mindfully sidestep the rules when the pressures are right. I use this to much delight in various places in Rails where I'm well aware of the fact that the call is to a private, but I choose to anyway.

To me, that's the essence of Ruby. Guidance, not constraints. Make it ugly instead of impossible.

Three cheers for a send that sidesteps visibility ;)!
--
David Heinemeier Hansson,
http://www.basecamphq.com/ -- Web-based Project Management
http://www.rubyonrails.org/ -- Web-application framework for Ruby
http://macromates.com/ -- TextMate: Code and markup editor (OS X)
http://www.loudthinking.com/ -- Broadcasting Brain

Marc Merlin wrote:

In other words, information hiding is a way of making software systems
resilient in the face of change. It is not simply a way "nanny"
programming languages try to keep "top-gun" programmers from getting their
job done.

Except that, if a private function is irrevocably private, it actually *does* occasionally keep top-gun programmers from getting their job done. Information hiding is a good thing, but absolute enforcement of information hiding is not a good thing, at least in Ruby. This probably precludes Ruby from certain applications.

The normal Ruby syntax enforces information hiding as you would expect, while using "send" is ugly and it stands out clearly. People that use "send" to subvert information hiding are fully aware that they are breaking the rules and introducing an ugly dependency on a hidden API into their system. Sometimes that is the right tradeoff for a good engineer to make.

Why should the creator of the "private" API be the one to decide, once and for all, that this is unacceptable? The creator cannot anticipate every situation that will occur in the future, they can only designate areas of relative instability using "private" and "protected".

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

Marc Merlin wrote:

...
In other words, information hiding is a way of making software systems
resilient in the face of change. It is not simply a way "nanny"
programming languages try to keep "top-gun" programmers from getting their
job done. Of course, for small projects with a restricted user base these
constraints hardly matter. If Ruby were intended to be only a prototyping
tool, then bypassing access controls would be no big deal. But Ruby
apparently is on the way to being adopted as a bona fide
progamming-language-in-the-large, as evidenced by such trailblazing
projects as the Rails framework. (I certainly hope so!) Consequently I
think that the adherence to a rigorous informtation hiding schema should be
taken seriously and mechanisms to bypass it should be brought into
question.

I agree; any mechanism for by-passing orderly program control should be viewed with suspicion. But such things need to be there, as the programmer must always be the ultimate arbiter.

Every modern language has such mechanisms; they are either explicit or buried, but they are there. Better they be made clear and well documented so all involved can make informed choices.

Even if strict data hiding was enforced there would be countless other ways to write poor code; I (sadly) have too much have proof of this. The end-user must always rely on the judgment of the developer, in any language.

I haven't looked at all that much of the Rails source code, so I don't know the they answer, but here's something to ponder: Were strict data + method access enforced, would Rails be (as) feasible?

Further, C is certainly well accepted as a mainstream language, and it allows for far more easier tomfoolery than does Ruby.

I don't view OO and data hiding as a way to hamstring advanced developers, but I do believe some languages gain traction precisely because their built-in constraints serve as an effective form of mob control for projects involving large numbers of inexperienced (and less expensive) developers who might otherwise run amok.

I believe, too, that it can be argued that these constraints lead to overly complex code that ages poorly compared to applications built using agile languages. While some might have a warm fuzzy feeling during production, you end up with code less resilient to change.

James

P.S.

I suspect concerns over malleable object boundaries are nearly identical to concerns over dynamic typing. Proper use of unit testing will do a lot more for ensuring robust code than either strict encapsulation or typing.

Ruby is too dynamic to do this:

$ ruby
class X; private; def a; puts 5; end; end
i = X.new
begin i.a; rescue Exception => e then puts e.class end
class X; public :a; end
i.a
NoMethodError
5

But then, there are ways to exploit it to not allow these things to happen, like redefining send and __send__ and method and running with $SAFE = 4

PGP.sig (186 Bytes)

···

On 29 Dec 2004, at 20:26, Marc Merlin wrote:

Consequently I
think that the adherence to a rigorous informtation hiding schema should be
taken seriously and mechanisms to bypass it should be brought into
question.

--
Eric Hodel - drbrain@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Marc Merlin wrote:

[...]
In other words, information hiding is a way of making software systems
resilient in the face of change. It is not simply a way "nanny"
programming languages try to keep "top-gun" programmers from getting their
job done. Of course, for small projects with a restricted user base these
constraints hardly matter. If Ruby were intended to be only a prototyping
tool, then bypassing access controls would be no big deal. But Ruby
apparently is on the way to being adopted as a bona fide
progamming-language-in-the-large, as evidenced by such trailblazing
projects as the Rails framework. (I certainly hope so!) Consequently I
think that the adherence to a rigorous informtation hiding schema should be
taken seriously and mechanisms to bypass it should be brought into
question.

I think #send should not be able to call private methods (from a proper OO perspective, not neccessarily mine ;-), but it should be able to call protected methods. Nevertheless, I think deciding whether a method should be declared as protected or private is not always easy, and I would not matter if there were only "protected" methods in Ruby (which means that they have to be called with "self" as receiver, regardless of the class they were defined). Of course there are for sure many situations where you'd want to have private methods.

What you want is probably this:

   class Object
     def send(id, *args, &block)
       if private_methods.include?(id.to_s)
         raise "private method `#{ id } called for #{ self }"
       end
       __send__(id, *args, &block)
     end
   end

That's the good thing with Ruby. Without the current behaviour of __send__ (or send), you could not implement what currently is possible (call private methods).

Regards,

   Michael

Brian Palmer wrote:

Then I would just have the interpreter do a #send with whatever the user typed in, and let #method_missing handle the "I don't understand what you mean" type messages.

I expect this would be a fairly easy system to compromise. Think of all the cross-scripting hacks that web developers have to guard against today, hence the tainted concept. If you really trust your users, or if you don't care what happens to your computer, then OK. Otherwise, you should maintain strict isolation between user input and executable code.

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

I agree with Glenn Parker that denying access to private methods will
unquestionably prevent programmers from accomplishing tasks that they
otherwise could, and I agree that Ruby programmers for the most part are
aware that they are breaking the rules by bypassing information hiding.
(The same could be said of denying access to object attributes, as well.)
I also agree that the creator of an implementation cannot anticipate all its
possible future uses.

By designating a method as a private the implementor is saying that its
appearance in the code is in some way incidental. To some extent that is
his or her call to make, although admittedly it may be wrong. I'm not
saying that this is the implementor's right in any proprietary way, I'm
saying that as a matter of fact the implementor has decided that some
behavior for the component that will be exhibited publically - the type, so
to speak - and the rest of its functioning will be hidden.

The motivation for hiding this functioning is actually an admission not of
omniscience but of uncertainty on the part of the implementor - uncertainty
whether the private methods will be retained in future versions of the
component or whether they will function identically if they are retained.
The same is true with any successor implementors who strive to preserve the
type of the software component.

Now I think it's all well and good if a Ruby programmer aware of the risks
undertakes to violate access restrictions in order to accomplish an
otherwise impossible (or exceedingly difficult) task. The rules of
informed consent would seem to apply and the chips would seemingly fall
where they may.

The problem occurs when the aware access-control dodger in turn creates an
software artifact used by other people. They themselves are unaware of the
fragility that has been introduced into software system upon which they are
relying. A "private" change in a component invisible to them - a change
not affecting the proper functioning of that component in the least - could
blow them out of the water.

[Perhaps this problem could be addressed by introducing another dimension of
"tainting" to indicate other forms of software risk. That's a topic for
another thread.]

In summary, implementors publish types. They and their successors retain
the perogative to change their implementations consistent with such types,
otherwise they have simply introduced a new type. The people placed at
risk by the subversion of the "type boundary" are not necessarily the
first-order clients of the software component, but others, maybe several
layers removed, who incorporate the subverting components into their
software creations.

I should be clear. Object#send isn't a big deal for me. Someone raised an
issue and I wanted to share my concerns. I have the utmost respect for the
Ruby community and am sympathetic to points on both sides of this question.

Cheers,
Marc Merlin

It goes both ways, you need a solid foundation to build on, agreed, but you
also need flexibility across the board. What separates private? Is it a
road-block or a sign-post? What's a sign-post going to do? Well, it will
_deter_. If that is a goal then perhaps a 'deter' directive is in order. On
the otherhand, if there are things necessarily private, does it indicate a
flaw in design? Is it rightful for Classes to have local namespace?

Or you could just say screw it and just reduce them to what they are, a Scope.
A Scope is just a callable container, a scope can be public, private,
protected, or deterred (and passive vs. active, see aop). Any one up for a

  public class String
  end

  %String{This is a new string}

or,

  String("This is a new string")

or Classicaly,

  String.new("This is a new string")

I believe it is things like this that Rails is teaching, but David has better
words... http://rubyonrails.org

T.

P.S.
Hmm... I wonder how fast Ruby method lookup would be if it was in a Database.
Then I could access through a marginally distinct map of nomenclature.