Private methods - only available to oneself?

M

minkoo.seo

Hi, all.

I'm a somewhat newbie in ruby realm, and trying to write some codes.
Yesterday, I've found very strange characteristics in ruby.

Please see the following:

irb(main):001:0> class Foo
irb(main):002:1> private
irb(main):003:1> def bar
irb(main):004:2> print "hi"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> class Foo
irb(main):008:1> public
irb(main):009:1> def duh
irb(main):010:2> f = Foo.new
irb(main):011:2> f.bar
irb(main):012:2> end
irb(main):013:1> end
=> nil
irb(main):014:0> f = Foo.new
=> #<Foo:0x2cdd2f0>
irb(main):015:0> f.duh
NoMethodError: private method `bar' called for #<Foo:0x2cdb7a8>
from (irb):11:in `duh'
from (irb):15
irb(main):016:0> quit

As you can see in the above, method "bar" is private to Foo. And that
method is called from another public method "duh". "duh" calls private
method of "f", which is not the instance where "duh" is called.

In all other languages, such as Java and C++, it is perfectly legal to
call private method as long as the method is called from methods of
the same class.

For example, the following complies in C++:

#include <iostream>

using namespace std;

class Foo
{
private:
void foo()
{
cout << "hi" << endl;
}

public:
void duh()
{
Foo f;
f.foo();
}
};

int main()
{
Foo f;
f.duh();
return 0;
}

I'm not saying that Ruby is wrong while the others are correct. I'm
just trying to figure out the "reason" of this strange behavior. Any
one can tell me?
 
K

Kent Sibilev

The short answer would be: because Ruby is not Java or C++.
The long answer is: in Ruby you can't invoke private methods by using
explicit receiver:

irb(main):001:0> class A
irb(main):002:1> def m; puts 'ok' end
irb(main):003:1> private :m
irb(main):004:1>
irb(main):005:1* def test
irb(main):006:2> m
irb(main):007:2> self.m
irb(main):008:2> end
irb(main):009:1> end
=3D> nil
irb(main):010:0> A.new.test
ok
NoMethodError: private method `m' called for #<A:0x3331d0>
from (irb):7:in `test'
from (irb):10
from :0
irb(main):011:0>

Kent.
 
M

Minkoo Seo

Thanks, Kent.

Yes, I know that Ruby is neither Java nor C++.

Let me put this way. Private methods should be called by an entity
which understand the internals of the object. Also, the entity will be
tightly coupled with the implementaion details.

In the code I've shown above, private method is called by the class
itself. I believe it is manifest that the class itself can not but
coupled with oneself. In addition, it is also sure that the object
understand the internal structure and implementation details.

That being said, is there still any reason to prohibit such a private
method access?
 
E

Erik Veenstra

f.instance_eval{bar} # Won't fail... !!!
Okay. Now I got totally confused. What's the purpose of
instance_eval?

Instance_eval evaluates the given block within the context of
the receiver. This means that bar is called from within the
context of f itself.

(You should have asked: "If we can do this, what's the purpose
of 'protected' or 'private'?"...)

gegroet,
Erik V. - http://www.erikveen.dds.nl/
 
M

Minkoo Seo

Thanks, Erik. I'm afraid that I'm not a native English spearker, so
sometimes it's not easy to express my own idea in exact English
expression.

Of course, I did look up the reference and found what instance_eval
does when being called. What I tried to ask was, as you stated,
"If we can do this, what's the purpose of 'protected' or 'private'?"

Thanks in advance.

Best,
Minkoo Seo
 
M

Minkoo Seo

I'm sorry Erik. I'm not native English speaker. So, sometimes it's not
easy to express what I have in my mind in English.

Yes, what I did want to know is "If we can do this, what's the purpose
of 'protected' or 'private'?"

Best,
Minkoo Seo
 
J

James Britt

Minkoo Seo wrote:
...
"If we can do this, what's the purpose of 'protected' or 'private'?"

To let you know when code is being used contrary to its design. The
idea is not to make things impossible, but to facilitate intention.

If you unwittingly call a private method, Ruby complains. But if you
still believe you have a good reason to call it, Ruby makes it possible.

Ruby assumes the developer is a grown-up.
 
P

Phrogz

I think the purpose of instance_eval is one of those "sharp knife"
things in Ruby. (Some other languages try to protect by not giving you
sharp knives. Ruby gives you sharp knives, and trusts that you know
enough not to hurt yourself.)

In Ruby, you can always use instance_eval to tweak the @instance
variables for an object. Even if 'private' and 'protected' were
enforced, this means that you can totally break the OOP encapsulation.

1) Any time you use #instance_eval, you should say to yourself "Damn,
this is a very sharp knife. I'd better be sure not to cut myself!"
Especially if you're messing wih the internals of a class you don't
know fully how it works.

2) If you are writing a class or module for use by others, they will
have access to the source code, and could rewrite it to allow things
you didn't intend. Use 'protected' and 'private' to indicate when the
methods should be called under normal circumstances. But it's not a
guarantee.
 
H

Hal Fulton

Minkoo said:
Thanks, Erik. I'm afraid that I'm not a native English spearker, so
sometimes it's not easy to express my own idea in exact English
expression.

Of course, I did look up the reference and found what instance_eval
does when being called. What I tried to ask was, as you stated,
"If we can do this, what's the purpose of 'protected' or 'private'?"

'private' is not like a locked door. It is like a sign saying "Do Not
Enter.'

Or look at it this way: It makes it "more difficult" to access private
vars (so that you will know you shouldn't), but doesn't make it
impossible (in case you really, really need to).


Hal
 
G

Gene Tani

Phrogz said:
2) If you are writing a class or module for use by others, they will
have access to the source code, and could rewrite it to allow things
you didn't intend. Use 'protected' and 'private' to indicate when the
methods should be called under normal circumstances. But it's not a
guarantee.

There's a few loopholes around private and protected, e.g. subclass a
class with private methods and declare them public in the subclass, but
one of them is closed in 1.9, you can't #send private methods anymore
(ok, you can #funcall them, ...)

http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9
 
D

dblack

Hi --

There's a few loopholes around private and protected, e.g. subclass a
class with private methods and declare them public in the subclass, but
one of them is closed in 1.9, you can't #send private methods anymore
(ok, you can #funcall them, ...)

I think there's still hope that that will disappear by 2.0 :)


David

--
David A. Black ([email protected])
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Private methods - only available to oneself?"
on Sun, 12 Feb 2006 02:19:27 +0900, (e-mail address removed) writes:

|> There's a few loopholes around private and protected, e.g. subclass a
|> class with private methods and declare them public in the subclass, but
|> one of them is closed in 1.9, you can't #send private methods anymore
|> (ok, you can #funcall them, ...)
|
|I think there's still hope that that will disappear by 2.0 :)

Do you mean you are expecting funcall's vanishment?

matz.
 
D

dblack

Hi --

Hi,

In message "Re: Private methods - only available to oneself?"
on Sun, 12 Feb 2006 02:19:27 +0900, (e-mail address removed) writes:

|> There's a few loopholes around private and protected, e.g. subclass a
|> class with private methods and declare them public in the subclass, but
|> one of them is closed in 1.9, you can't #send private methods anymore
|> (ok, you can #funcall them, ...)
|
|I think there's still hope that that will disappear by 2.0 :)

Do you mean you are expecting funcall's vanishment?

Yes, kind of. I'm worried that we'll get a lot of "Which one does
private methods, and which one doesn't?", and people will just have to
try to memorize it. The names themselves don't express the
difference, to me.

But I know you didn't like my send/send! idea :)


David

--
David A. Black ([email protected])
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
 
J

Jacob Fugal

There's a few loopholes around private and protected, e.g. subclass a
class with private methods and declare them public in the subclass, but
one of them is closed in 1.9, you can't #send private methods anymore
(ok, you can #funcall them, ...)

An easier bypass, which I don't think[1] is closing in 1.9/2.0: reopen
the class.

galadriel:~$ cat > test.rb
class Foo
private
def bar
puts "bar"
end
end

f =3D Foo.new
begin
f.bar
rescue
puts "Exception raised"
end

# ... later ...

class Foo
public :bar
end

g =3D Foo.new
g.bar

galadriel:~$ ruby test.rb
Exception raised
bar

Jacob Fugal
 
A

Adam P. Jenkins

Phrogz said:
1) Any time you use #instance_eval, you should say to yourself "Damn,
this is a very sharp knife. I'd better be sure not to cut myself!"
Especially if you're messing wih the internals of a class you don't
know fully how it works.

The other main thing to be concerned about when accessing private
methods is that their behavior, or even existence, may change in the
next version of the class. Furthermore, except for debugging purposes,
I'd say that if you find yourself needing to access private class
methods from outside the class, it's because the class in question needs
a redesign, or has a bug.

That said, I do think that Ruby's decision to make private mean "only
accessible to oneself" as opposed to "only accessible to class members"
is debatable. In fact I don't see the point of it from a practical
point of view. It seems to me that the main reasons for making methods
private is advertise that a) they're implementation details that may
change without notice in new versions of the class, and b) they may
require inside knowledge of the class's workings to use correctly. Both
of these reasons would be just as well served by allowing other
instances of the same class to access private members, so I don't see
the point of the extra restriction. Anyone?

Adam
 
D

Daniel Nugent

Adam, there's two things here:

1) When you're using an object in Ruby, the *only* way to interact
with it is to send messages to it. This is uniform across the
language and a damned good idea if you ask me. Mixing methods with
accessing fields is a bad idea in my book.

2) Ruby provides the Java private method access level with protected,
as mentioned earlier in the thread. Yes, it requires you explicitly
declare member variables as protected, but if you're dead set on
giving objects access to all the instance variables, you can
definitley do that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,187
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top