Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: Howto keep private methods private?

by kyle (Abbot)
on Sep 14, 2007 at 12:21 UTC ( [id://638996]=note: print w/replies, xml ) Need Help??


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.

Replies are listed 'Best First'.
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!

    -stvn

      private methods should not block a perfectly valid (inherited) public method from being called.

      Why not? You're advocating a workaround to allow someone to name a private method the same as a public one. That's asking for trouble.

        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

        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.

        -stvn

      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:

      1. call private methods as function (no risk of hijacks)
      2. don't name public methods with a leading underscore (always safe to add _func:s, if you follow (1))

      lodin

      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.

        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 :)

        -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://638996]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2025-07-08 16:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.