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.
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?
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
=> 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
irb(main):011:0>
Kent.
···
from :0
On 2/11/06, minkoo.seo@gmail.com <minkoo.seo@gmail.com> wrote:
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.
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?
Private methods are only callable from within the same objects.
In your, situation, that's not happening. You are calling bar
of one Foo object from another Foo object.
You should use "protected" to "define" that behavior.
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?
Ruby doesn't have Java's "public" (anyone may access) and "private"
(same-class only), it has one additional level with better names:
public - anyone may access
protected - same class only, please
private - only from the instance itself
"Mom, my brother is messing with my hair! Protect me!"
"Your hair *is* protected, that's the problem. Make it private and then
he won't be able to touch it."
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, 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).
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.
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
I do not understand why within the class definiton the Ruby interpreter
distinguishes between implicit and explict calls to self.
i.e
Class Foo
def foo_one
bar
end
def foo_two
self.bar
end
def bar
puts "In Bar"
end
private :bar
end
f = Foo.new
f.foo_one
-> "In Bar"
f.foo_two
-> NoMethodError: private method `bar' called for
This leads to the inference that self !=== <implicit self> which strikes
me as decidedly odd. Self is either always self or it is not and if not
then what is it? Whether self is declared as the the receiver or left
for the interpreter to contextually establish should make no difference
to the effect of a private method. Is this difference due to a parsing
limitation or a purposeful design decision that serves some intent I
cannot presently fathom? If the latter, then what is the purpose served
by this disticntion between an explicit and implicit self receiver?
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, ...)
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?
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
I do not understand why within the class definiton the Ruby interpreter
distinguishes between implicit and explict calls to self.
i.e
Class Foo
def foo_one
bar
end
def foo_two
self.bar
end
def bar
puts "In Bar"
end
private :bar
end
f = Foo.new
f.foo_one
-> "In Bar"
f.foo_two
-> NoMethodError: private method `bar' called for
This leads to the inference that self !=== <implicit self> which strikes
me as decidedly odd. Self is either always self or it is not and if not
then what is it? Whether self is declared as the the receiver or left
for the interpreter to contextually establish should make no difference
to the effect of a private method. Is this difference due to a parsing
limitation or a purposeful design decision that serves some intent I
cannot presently fathom? If the latter, then what is the purpose served
by this disticntion between an explicit and implicit self receiver?
I'm mostly guessing, but I imagine because it would be hard to
establish that exception to the rule, and the exception would serve no
purpose. Also, I think of self as a *representation* of the current
object. So when the interpreter sees:
x
it doesn't literally stick "self" on the front; it just sends the
message to the current object.