Forum: Ruby Private methods not so private?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
900885f72f544f27afa77c6e1758e43b?d=identicon&s=25 Frank Meyer (turing)
on 2007-08-02 00:02
Hello,
I'm using Ruby 1.8.2 and I'm reading the book "Programming Ruby 2nd
edition". In this book they say, that Ruby implements private methods by
not allowing another receiver than "self". After reading this, I tried
the following:

class Test
 private
 def print_hello
  puts "Hello everyone!"
 end
end

t = Test.new
t.send( "print_hello" )


This program runs just fine and prints "Hello everyone!".



Is this behaviour to be expected?



Turing
Ad7805c9fcc1f13efc6ed11251a6c4d2?d=identicon&s=25 Alex Young (regularfry)
on 2007-08-02 00:10
(Received via mailing list)
Frank Meyer wrote:
>  end
> Is this behaviour to be expected?
Yes - send trumps private.  Private in Ruby is more of a guideline than
a rule.  The implementer is trying to tell you not to go there, but you
can get around it if you really need to.
90a73d9875462aaa9fab2feffafbffe7?d=identicon&s=25 Ben Bleything (Guest)
on 2007-08-02 00:11
(Received via mailing list)
On Thu, Aug 02, 2007, Frank Meyer wrote:
> This program runs just fine and prints "Hello everyone!".
>
> Is this behaviour to be expected?

Yes.  send bypasses protection levels, for reasons I'm not really clear
on.  If I were to hazard a guess, it would be that what you send is
eval'ed inside the context of the object, thereby making self the
receiver, but that's a total guess.

Test.new.print_hello will cause the error you expect.

As a sidenote, upgrade your ruby ;)

Ben
Aee77dba395ece0a04c688b05b07cd63?d=identicon&s=25 Daniel Berger (Guest)
on 2007-08-02 02:43
(Received via mailing list)
On Aug 1, 4:06 pm, Alex Young <a...@blackkettle.org> wrote:
> >   puts "Hello everyone!"
> Yes - send trumps private.  Private in Ruby is more of a guideline than
> a rule.

It's a guideline in any language.

I think people tend to think of 'private' as some sort of security
enforcement. It's not. It just means, "You aren't supposed to access
this method directly. If you go out of your way to do so, I am not
responsible for the consequences".

The advantage of allowing send to access private methods is that it
allows you to test private methods. :)

Regards,

Dan
48e8a52db22ee2eeabb994dced226773?d=identicon&s=25 Skye Shaw!@#$ (Guest)
on 2007-08-02 04:45
(Received via mailing list)
On Aug 1, 5:42 pm, Daniel Berger <djber...@gmail.com> wrote:
>
> > > This program runs just fine and prints "Hello everyone!".
>
> > > Is this behaviour to be expected?
>
> > Yes - send trumps private.  Private in Ruby is more of a guideline than
> > a rule.
>
> It's a guideline in any language.
>
> I think people tend to think of 'private' as some sort of security
> enforcement. It's not.

It is in C++ and Java, maybe even VB, if I recall... (I try not to
recall VB).
Well, maybe not a "security enforcement" but a visibility and/or
invocation restriction.

My JVM even gives me an IllegalAccessException when I try to access an
private Method at runtime via reflection.
Caf38c89d40443a858741b61ac6d82de?d=identicon&s=25 Dan Zwell (Guest)
on 2007-08-02 10:43
(Received via mailing list)
Ben Bleything wrote:
>>
>
> As a sidenote, upgrade your ruby ;)
>
> Ben
>
>

Ben,

It is always possible to run private methods, change class variables,
etc. The way to do it is to reopen the class (or add an instance method)
that calls the private method or sets/gets the variable we need. Since
it's possible, why not make it easier? Ruby tries not to impose on what
the user can do, so we have foo.send, foo.instance_variable_set, and
foo.instance_variable_get.

Dan
B3b452d7c2effcadb0ffa3dd65eae19f?d=identicon&s=25 "Jørgen P. Tjernø" (Guest)
on 2007-08-02 13:29
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Daniel Berger wrote:
> [ .. snip .. ]
> The advantage of allowing send to access private methods is that it
> allows you to test private methods. :)
Isn't that a Bad Practice (tm)? Private methods are mostly meant for the
internals of a class, and a test should really only test how the class
interacts with the rest of the world - right? (i.e. public methods)

I might've missed the whole point, so this post contains Many
Questionmarks. ;-)

Kindest regards, Jørgen P.
Tjernø.-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGsbDiUMzc1WGo4zgRAoJ3AJ9MtInhJTZS9Uq1ABXwxxN9rwkeVACffYBG
+iCp8nwruwSH/WzNSAsbQp8=
=ndYq
-----END PGP SIGNATURE-----
E257c17034ca33ea3f75574f6b22e402?d=identicon&s=25 dohzya (Guest)
on 2007-08-02 13:43
(Received via mailing list)
Le jeudi 02 août 2007 à 20:28 +0900, "Jørgen P. Tjernø" a écrit :
>
> -----END PGP SIGNATURE-----
>

It is a root of bad practices, but it may be necessary... I think a good
principe is : use public methods only of others's libraries, and use
instance_eval (etc) of yours when you need it, and if there is
collaboration between classes (like friendly classes of C++).
Thus you will be able to keep your model safe.
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 unknown (Guest)
on 2007-08-02 13:45
(Received via mailing list)
Hi --

On Thu, 2 Aug 2007, "Jørgen P. Tjernø" wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Daniel Berger wrote:
>> [ .. snip .. ]
>> The advantage of allowing send to access private methods is that it
>> allows you to test private methods. :)
> Isn't that a Bad Practice (tm)? Private methods are mostly meant for the
> internals of a class, and a test should really only test how the class
> interacts with the rest of the world - right? (i.e. public methods)

No; you definitely want to test your private methods too.  First of
all, if you're writing a class, you need to test its internals;
nothing should be a "black box" for the tests.  Second, private
methods are actually available to the world, even without send.  They
just have to be called the right way:

   puts "Hi"
   class C
     attr_accessor :x
   end
   C.class_eval { define_method "y" }

puts, attr_accessor, and define_method are all private, but you'd
certainly want to test them if you had written them.


David
90a73d9875462aaa9fab2feffafbffe7?d=identicon&s=25 Ben Bleything (Guest)
on 2007-08-02 17:13
(Received via mailing list)
On Thu, Aug 02, 2007, Dan Zwell wrote:
> the user can do, so we have foo.send, foo.instance_variable_set, and
> foo.instance_variable_get.

Right.  I was just trying to answer the original question :)

Ben
900885f72f544f27afa77c6e1758e43b?d=identicon&s=25 Frank Meyer (turing)
on 2007-08-02 20:00
Hello everybody,
thanks for your explanations. And I didn't know that ruby allows the
reading and setting (and even creation) of instance variables.

What does class_eval do?



And actually I'm using Ruby 1.8.6 I confused the version number with
those in the book.



Turing
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2007-08-02 20:39
(Received via mailing list)
On 8/2/07, dblack@rubypal.com <dblack@rubypal.com> wrote:
> >> allows you to test private methods. :)
> > Isn't that a Bad Practice (tm)? Private methods are mostly meant for the
> > internals of a class, and a test should really only test how the class
> > interacts with the rest of the world - right? (i.e. public methods)
>
> No; you definitely want to test your private methods too.

Conventional wisdom in the Agile/TDD community is that you shouldn't
be testing private methods. The reasoning goes something like this:

1. If you're doing TDD, you're sending messages to objects that other
objects in your system will send. The corresponding methods should be
public.

2. In TDD, private methods appear through refactoring, and therefore
are already tested implicitly through the tests of public methods.

3. When you feel the need to add tests on private methods (which have
appeared through refactoring), it should be considered a sign that a
new object is wanting to be born and should be extracted out into a
new class.

My sense is that some of this thinking is a product of the fact that
testing privates in Java means using reflection, resulting in
refactoring inefficiencies. In Ruby, testing privates is fairly easy
and we don't really have the refactoring tools that the Java community
has, so refactoring in Ruby tends to be much more manual anyhow.

That said, I think the OO design questions that get raised are worthy
of exploration when you feel the need to test something private.

WDYT?
90a73d9875462aaa9fab2feffafbffe7?d=identicon&s=25 Ben Bleything (Guest)
on 2007-08-02 20:55
(Received via mailing list)
On Fri, Aug 03, 2007, Frank Meyer wrote:
> thanks for your explanations. And I didn't know that ruby allows the
> reading and setting (and even creation) of instance variables.

Yup.  That's what @something variables are.

> What does class_eval do?

It's like instance_eval, but evaluates in the context of a class
instead.  Hark:

str = "foo"
str.instance_eval {length}
=> 3 (same as calling str.length)

str.class.class_eval {def foo; return 'bar'; end}
str.foo
=> 'bar' # effectively the same as re-opening the class

I'm sure there are other subtleties involved, but that's the top-level
view.

Ben
44869413a67ee5dc2d7d36533d055ecd?d=identicon&s=25 Dan Yoder (Guest)
on 2007-08-02 20:59
(Received via mailing list)
I've written some interesting use cases concerning send here. FYI: my
understanding is that 1.9 will change the semantics of send so that it
no longer accesses private methods.

http://groups.google.com/group/comp.lang.ruby/brow...

Regards,
Dan
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 unknown (Guest)
on 2007-08-02 21:31
(Received via mailing list)
Hi --

On Fri, 3 Aug 2007, David Chelimsky wrote:

>>>> The advantage of allowing send to access private methods is that it
> 1. If you're doing TDD, you're sending messages to objects that other
>
> My sense is that some of this thinking is a product of the fact that
> testing privates in Java means using reflection, resulting in
> refactoring inefficiencies. In Ruby, testing privates is fairly easy
> and we don't really have the refactoring tools that the Java community
> has, so refactoring in Ruby tends to be much more manual anyhow.
>
> That said, I think the OO design questions that get raised are worthy
> of exploration when you feel the need to test something private.
>
> WDYT?

My tendency is to think that the public/private distinction in Ruby
does not overlap very closely with the line between methods you're
likely to use from outside and methods you're not, mainly for two
reasons.

First, private instance methods of Kernel, like raise and sprintf:
these are not behind the black curtain, but are private so as to be
callable in a receiverless way.  I'd expect them to be tested.

Second, quick and frequent scope and self-scope changes:

   class C
     define_method ...
   end

etc.  define_method, like raise and sprintf, won't go away because of
refactoring; it's a private method, but part of the interface one is
expected to use (rather than simply a by-product of the implementation
of some other such method).

That said, it may be that there are private methods one wouldn't test,
namely those that are really part of the black box, where all you
really need to know is whether the black box produces the right
answer.  But I think that's just a subset of private methods,
certainly in core/standard Ruby and quite possibly in other Ruby code.


David
This topic is locked and can not be replied to.