in reply to Re^2: Private and Protected class methods (accidental)
in thread Private and Protected class methods

My first impression of the above solution is that is appears broken anyway {it seems like it should be seeing if (caller(2)'s package)->can(caller(1)'s method name)}. So I probably don't understand the point of it.

Actually, no (I have tested this). The subroutine name from caller is in the form Package::sub_name, where Package is always the name of the definining package. So, I check to see "who invoked the sub that called me?" and see if that package can sub_name. It works. It took me a while to get right, but it works.

And I doubt I'd use inheritance to get this helper subroutine available to every class that wants to define protected subs.

That's not exactly what I'm doing. This particular client has asked me to write an organization-wide base class (as in "all our classes will inherit from this"). This feature is being included there, so it must propogate via inheritance. That's not a design decision, it's a requirement.

I'm not sure that the way @ISA is searched using can() is the best approach here.

See, it's the only way I know of. I'd love to hear if there was another, better way. Care to elaborate?

No, I suspect that my OO "best practices" would break this code.

Can you be more specific? What do you do that would break this? How would it break?

I also suspect that stepping back and looking at the specific problem may lead to a solution other than "protected methods".

Like I said in my intro -- my personal feeling is to simply establish a coding standard that has a convention for naming protected and private methods, and let the code reviews, etc. catch things. That said, I also understand my client's point of view -- sometimes it's nice to kvetch about things like this (like the Perl::BestPractices module).

The central point being that the ability to define private and protected methods is a requirement of my client, regardless of how I feel about them, so I need to find a workable solution that won't cause too many issues. You seem to suggest that the solution I'm proposing would cause some issues, but I would appreciate expansion of what those might be and what I have to consider to devise a work-around.

<radiant.matrix>
A collection of thoughts and links from the minds of geeks
The Code that can be seen is not the true Code
I haven't found a problem yet that can't be solved by a well-placed trebuchet
  • Comment on Re^3: Private and Protected class methods (accidental)

Replies are listed 'Best First'.
Re^4: Private and Protected class methods (caller)
by tye (Sage) on Sep 06, 2006 at 20:26 UTC

    But caller() is being used from PROTECTED(), and I'd think you'd want to know that whoever is calling the _protected_method() ->can( "_protected_method" ) so I'd think you'd want to grab the method name from caller(0) not caller(1) (after experimenting to figure out how many levels up caller($n) looks since the documentation isn't clear enough). But I freely admit that I don't grok the situtation and so could easily be mistaken (in particular, it looks like the fourth value from caller isn't as I expected).

    See, it's the only way I know of. I'd love to hear if there was another, better way.

    My first impression is that I'd check (calling package)->isa(called package). But I haven't thought any of the options through enough to declare any of them "better".

    Given your requirements, I'd name this method _PROTECTED() since it isn't meant to be used by your object users.

    See Re: How do YOU do OO in Perl? (constant offsets) and Re: OO - best way to have protected methods (packages) for some quick examples of my use of packages that might break your assumptions. In particular, consider a case where I've "exported" a sub into my method namespace. So caller will return the name of the package that the code was compiled into which isn't helpful here. Will caller return the name of the sub as it was defined or as it was called (since I might be calling My::Class::_protected_sub which got into My::Class by exporting Some::Other::Package::_other_name, for example)? Try this example:

    package Caller::CompiledIn; sub origCaller { shift(@_)->_protected_method(); } package Protected::CompiledIn; sub origProtected { my $self= shift(@_)->_PROTECTED(); ... } package main; @Protected::Class::ISA= 'Your::Uber::BaseClass'; *Protected::Class::_protected_method= \&Protected::CompiledIn::origPro +tected; @Caller::Imported::ISA= 'Protected::Class'; *Caller::Imported::importedCaller= \&Caller::CompiledIn::origCaller; my $obj= bless [], 'Caller::Imported'; $obj->importedCaller();

    - tye        

      I'd think you'd want to know that whoever is calling the _protected_method() ->can( "_protected_method" )

      That's correct, and actually -- it works. The level for caller took some playing with, but caller(1) turns out to be right: caller(0) would be the _protected_sub itself, while caller(1) is whomever called the _protected_sub.

      I'd name this method _PROTECTED()

      Good point, noted.

      In particular, consider a case where I've "exported" a sub into my method namespace.

      Hm, interesting. I hadn't considered what would happen when exporting methods like that, since I've never had need to do things like that. I will have to bring it up with my design team and see what to do about it. That particular case seems to work (though I don't entirely understand why), but I can see where more complicated cases in the same class might cause problems.

      Thank you, and ++;

      <radiant.matrix>
      A collection of thoughts and links from the minds of geeks
      The Code that can be seen is not the true Code
      I haven't found a problem yet that can't be solved by a well-placed trebuchet