http://www.perlmonks.org?node_id=368618

pijush has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I am trying to learn a OO programming in perl. I have writtten following code to learn inheritance.

{ package Animal; sub new { my $class = shift; my $name = shift; bless \$name, $class; } sub name { my $self = shift; ref $self ? $$self : "an unnamed $self"; } sub speak { my $class = shift; print "a $$class goes ", $class->sound, "!\n"; } sub eat { my $self = shift; my $food = shift; print $self->name, " eats $food.\n"; } } { package Horse; @ISA = qw (Animal); sub sound {"neigh"}; } { package Sheep; @ISA = qw (Animal); sub sound {"blahhhhhhhh"}; } my $horse1 = Horse->new("H1"); $horse1->speak; print "Horse sounds ", Horse->sound, "\n"; $horse1->eat("hay"); Sheep->eat("grass"); Sheep->speak;
In the above code every methods present in Animal can be accessed by Horse or Sheep object. But if I want to add a private method to Animal class, how can I implement this? I tried to find out on Net and found out there are modules present public, private, but if I want to implement without using those modules, how can I implement this feature?
Thanks in advance
-Pijush

Replies are listed 'Best First'.
Re: How can I add private data/methods in parent class?
by PodMaster (Abbot) on Jun 22, 2004 at 07:02 UTC
    I tried to find out on Net and found out there are modules present public, private, but if I want to implement without using those modules, how can I implement this feature?
    Why don't you look inside those modules to see how they work?

    This is not a very easy problem to solve in perl. Here's one possible approach (though not foolproof):

    use strict; package BOB; use Carp; use base 'IO::File'; use overload(); sub _pRiVaTish { my $self = shift; my ($package, $filename, $line) = caller; carp "YOU MUST NOT CALL THIS METHOD YOU, YOU AIN'T BOB!!!" unless $filename eq __FILE__ and 0 == index overload::StrVal($self), __PACKAGE__,0; return 'beep'; } package BIB; use vars '@ISA'; @ISA='BOB'; 1; package main; my $bib = BIB->new(); $bib->_pRiVaTish(); __END__ YOU MUST NOT CALL THIS METHOD YOU, YOU AIN'T BOB!!! at private.methods +.pl line 28
    And just in case(:

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: How can I add private data/methods in parent class?
by dakkar (Hermit) on Jun 22, 2004 at 14:00 UTC

    OK, everybody is going to give you different answers, from "you can't do that" to "you shouldn't do that"... I'll try to explain the "why"

    Perl has, per se, non concept of "private" methods: a package is a name space: it contains names for things (subroutines, but also variables, etc). OOP in Perl is based on the fact that, by blessing a reference, you attach to it the name of a package. Then, when you use it with the "arrow notation", Perl looks at the name of the package you have attached to the reference, and starts from it to look for a subroutine with the name you specified (I assume you know how the inheritance works). At no point Perl consults some attribute of the reference, the packages, or the subroutines, to discover if it was OK for you to call that subroutine.

    This is a design choice. Maybe not the best one (Perl6 will have proper privacy of members), but the one that has been made. The idea was that it was both easier and more flexible to do it this way, and that the programmers would just avoid to step on each other's toes.

    There are several modules out there that muck with the inheritance, add methods to other classes, and generally behave pretty poorly if you judge them "by the book". But the main goal, in Perl, is to get the job done. If you need strong encapsulation and privacy, there are modules that can give them to you (you'll get plenty of pointers from other people, I'm feeling a bit lazy at the moment); and the reason that you can get them is that Perl does not provide them itself, but instead leaves everything wide open for anybody to tinker with.

    Oh, as a sidenote, Perl6 will both have privacy and encapsulation, and permit to tinker with classes at will. It will just be a little better presented ;-)

    -- 
            dakkar - Mobilis in mobile
    

    Most of my code is tested...

    Perl is strongly typed, it just has very few types (Dan)

      Thank you all the monks who have replied with so much explation.
      Today I was reading Programmaing Perl, 3rd Edition by Larry Wall, Tom Christiansen and Jon Orwant and found out a way to modify the code which I posted in my previous mail to implement private method. The modified code is
      { package Animal; use Carp; use overload(); sub new { my $class = shift; my $name = shift; bless \$name, $class; } sub name { my $self = shift; ref $self ? $$self : "an unnamed $self"; } sub speak { my $class = shift; print "a $$class goes ", $class->sound, "!\n"; } sub eat { my $self = shift; my $food = shift; print $self->name, " eats $food.\n"; } my $private_method = sub { my $self = shift; print "From private method\n"; }; sub Private_Method { my $self = shift; print "kk::$self->{private_var}\n"; if (0 == index overload::StrVal($self), __PACKAGE__,0) { $self->$private_method(); } } } { package Horse; use vars '@ISA'; @ISA = qw (Animal); sub sound {"neigh"}; } { package Sheep; use vars '@ISA'; @ISA = qw (Animal); sub sound {"blahhhhhhhh"}; } my $horse1 = Horse->new("H1"); $horse1->speak; print "Horse sounds ", Horse->sound, "\n"; $horse1->eat("hay"); Sheep->eat("grass"); Sheep->speak(); #$horse1->Private_Method; #I can not access this Animal->Private_Method;
      Is this method OK? Is there any loophole? Any help will be really appreciated.
      Thanks in advance.
      -Pijush
Re: How can I add private data/methods in parent class?
by saintmike (Vicar) on Jun 22, 2004 at 05:56 UTC
    I am trying to learn a OO programming in perl. I have writtten following code to learn inheritance.
    By coincidence, this is exactly the same code as in merlyn's column, you magnificent devil, you!

    As for private methods in Perl, read this thread.

      As I mentioned that I am just learning how to write OO programe, so I have used the code present in the documentation and try to add my code to explore OO features which are present in other language (such as C++) and how can I implement in Perl?
Re: How can I add private data/methods in parent class?
by ihb (Deacon) on Jun 22, 2004 at 13:54 UTC

    I think the real question you should ask yourself is why you want them to be private. Is it so that no one will be able to call them? If that's the case, you usually do well with just documenting them to not be called. I've never felt the need to "by force" hinder anyone from calling any of my methods.

    However, if it's because you don't want anyone to accidently overload your methods you could simply not call your method like a method but rather as a function, which is what a private method call is in this context. I usually do     _foo($self => @args); and then no subclass can overload my _foo by adding it's own _foo. If you know which code you want to call, then call that code directly.

    Note that this isn't done to force any subclass to not call _foo, but rather prevent any subclass from accidently overloading _foo with its own "private" method. This is particularily apparent for _init methods.

    ihb