in reply to Howto keep private methods private?
Class::Std creates something like this:
sub private {
my $caller = caller;
croak "Can't call private method from $caller"
if $caller ne __PACKAGE__;
}
That's paraphrased. If you want, you can check caller against an access list or do other funny things.
Re^2: Howto keep private methods private?
by stvn (Monsignor) on Sep 14, 2007 at 14:52 UTC
|
That approach to method privacy is fundementally broken, consider this:
package Foo;
sub new { bless {} => shift }
sub baz { "Hello from Foo::baz" }
package Bar;
use base 'Foo';
sub baz { # baz is private ...
my $caller = caller;
croak "Can't call private method from $caller"
if $caller ne __PACKAGE__;
"Hello from Bar::baz (private)";
}
sub call_baz { (shift)->baz }
package main;
Bar->new->baz; # BOOM!
This is incorrect behavior, private methods should not block a perfectly valid (inherited) public method from being called. The only way to get proper behavior is to not add the private method to the class's symbol table, which means doing it like so:
package Foo;
sub new { bless {} => shift }
sub baz { "Hello from Foo::baz" }
package Bar;
use base 'Foo';
my $baz = sub { # baz is private ...
my $caller = caller;
croak "Can't call private method from $caller"
if $caller ne __PACKAGE__;
"Hello from Bar::baz (private)";
};
sub call_baz { (shift)->$baz() }
package main;
Bar->new->baz; # no more BOOM!
| [reply] [d/l] [select] |
|
| [reply] |
|
You're advocating a workaround to allow someone to name a private method the same as a public one.
Not necessarily. It may be the other way around. The parent may add the public method after the private method was created by the subclasser. Indeed, if the parent class' author and child class' author are different persons, the latter is doing a risky task to begin with. But regardless, if someone's using the subclass and want to use this new shiny method, the naive croak()ing implementation may needlessly break code that would otherwise work.
lodin
| [reply] [d/l] |
|
You're advocating a workaround to allow someone to name a private method the same as a public one. That's asking for trouble.
Not at all, I am advocating that a chosen system for creating private methods should not restrict me from doing something as stupid as naming a private method after an inherited public one. After all, this is perlmonks.org and not www.bsdm-javacafe.org right? ;)
but seriously ...
private methods should not block a perfectly valid (inherited) public method from being called.
Why not?
Because, privacy (IMO) means it is only visible and relevant to the local class. So what I do in my bedroom... uhm... i mean my class, is up to me and the government ... ah,... uhm... I mean other programmers, have no right to tell me what to do.
Okay, so i am not being totally serious. But my point is that a generalized system of method privacy should be really truely private, and therefore invisible to anything outside of my class, and only applicable/relevant within my class.
| [reply] |
|
private methods should not block a perfectly valid (inherited) public method from being called. The only way to get proper behavior is to not add the private method to the class's symbol table
I agree, kind of. I agree with the problem description and it's a fundamental issue with Perl's OO mechanism. I don't agree with your solution. (It's not completely clear you actually suggest people do use lexicals though.)
However, if you only want to make sure you don't block a parent method you can proxy the method call using goto &subname; (and possibly override can if there is any uncertainty as to whether the parent method exists or not), like
sub baz { # baz is private ...
goto &{$_[0]->can('SUPER::baz') || \&error}
if caller ne __PACKAGE__;
return "Hello from Bar::baz (private)";
}
But this solution only solves half the problem with having private methods. It doesn't solve the problem of a child accidentally hijacking the call. So for me it's not good enough to make it worth the trouble.
My real issue with the lexical approach is this. If you extend your concept, then you can't write or import utility functions either, as they might block a parent's methods. You'd only be allowed to put public methods in the symbol table. But that's just too much a mess. So unless you use an OO framework that solves this for you, you just have to make sure you don't have private methods or (imported) functions that clash with any parents' method. It adds some danger, but subclassing a class you don't control yourself is already dangerous for several other reasons.
This is my rationale behind the paradigm described here, which takes the middle road:
- call private methods as function (no risk of hijacks)
- don't name public methods with a leading underscore (always safe to add _func:s, if you follow (1))
lodin | [reply] [d/l] [select] |
|
I think if I inherit and override a public method with one that is private (or otherwise breaks the public interface), that's certainly rude, but I would not say that's a problem with the way the privacy is implemented. Perhaps we have different definitions of privacy at work here. I was trying to make a method that outsiders cannot call. You appear to want a method that outsiders cannot see at all.
| [reply] |
|
I was trying to make a method that outsiders cannot call. You appear to want a method that outsiders cannot see at all.
But they can call your method, it blows up in thier face, but they can call it.
I think if I inherit and override a public method with one that is private (or otherwise breaks the public interface), that's certainly rude, but I would not say that's a problem with the way the privacy is implemented.
Yes, it is incredibly rude given your definition of privacy. But if you were to be able to write that private method, and only have the local class use it, and all other subclasses use the original private one. It wouldnt be very rude then, because only the local class would need to know. Everyone else could just go about thier own merry way :)
| [reply] |
|
|