CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
private and protected methods

 

First page Previous page 1 2 Next page Last page  View All


ChopperCharles
Novice

Apr 3, 2012, 7:57 AM

Post #26 of 32 (2796 views)
Re: [wickedxter] private and protected methods [In reply to] Can't Post

Actually, I tried that last night and that helped some, but for some reason I'm getting undef as the first entry in my array when it's stored in $self.

So, inside a hash I'm guessing that since I can add anything at any time, regardless of the fact I'm using strict... that means somehow when I try and clear the array I'm adding an extra undef in?

How do I correctly clear and update an existing entry in the hash?

Charles.


budman
User

Apr 3, 2012, 8:18 PM

Post #27 of 32 (2793 views)
Re: [ChopperCharles] private and protected methods [In reply to] Can't Post

 
You would need to store the values in an anonymous array


Code
push @{  $self->{"_StructArray"} },  $element; 

push @{ $self->{"_StructArray"} }, @array;

push @{ $self->{"_StructArray"} }, ( $e1, $e2, @array);

# for array of hashes
push @{ $self->{"_StructArray"} }, { a=>1, b=>2 };

# or just a hash
$self->{"_StructArray"}{a} = 1;
$self->{"_StructArray"}{b} = 2;


To access them:


Code
use Data::Dumper; 
print Dumper( $self->{"_StructArray"} );

print $self->{"_StructArray"}[0];

foreach my $i ( @{ $self->{"_StructArray"} } ) {
print "$i\n";
}

# for array of hashes
foreach my $i ( @{ $self->{"_StructArray"} } ) {
foreach my $k (sort keys %{$i}) {
print "$k $i->{$k}\n";
}
}


Note: When key names start with an underscore, you should quote the key name as it may lead to issues with strict pragma.

I took a look at Class::Struct. My quick guess is that it takes each key you add in the struct method and auto-generates a setter and getter.


Code
$element_value = $obj->s;           # element value 
$obj->s('new value');


In order for your object to work like this, you would need to create the setter and getters for each key. This can be done by the AUTOLOAD to create the getter/setter on the fly. Otherwise, it's pretty monotonous. For what it's worth, to save time, headaches, and use proven well tested code - use Moose.


Code
sub s { 
my ($self) = shift;
if (@_) { $self->{'_Struct'}{s} = shift }
return $self->{'_Struct'}{s};
}
sub t {
my ($self) = shift;
if (@_) { $self->{'_Struct'}{t} = shift }
return $self->{'_Struct'}{t};
}


These can be pretty repetitive and you notice a pattern.
This is the idea behind Class::Struct, you can use AUTOLOAD, or better maybe to build it at compile time using BEGIN.

The attributes should be unique, or you can override existing subs.


Code
# handle undefined subs 
package tester;
BEGIN {
my @attribs = qw(s t u);
for my $attrib ( @attribs ) {
no strict 'refs';
# add getter/setter method
*{"$attrib"} = sub {
my $self = shift;
if (@_) { $self->{'_Struct'}{$attrib} = shift };
return $self->{'_Struct'}{$attrib};
};
}
}

sub new {
my $class = shift;
my $self = {};
$self->{'_Struct'} = {};
bless ($self, $class);
return $self;
}
1;

#!/usr/bin/perl
use strict;
use warnings;
my $k = tester->new();
$k->s(1);
$k->t(2);
$k->u(3);
printf "s = %s\nt = %s\nu = %s\n", $k->s, $k->t, $k->u;


Output:
s = 1
t = 2
u = 3


(This post was edited by budman on Apr 3, 2012, 8:20 PM)


budman
User

Apr 3, 2012, 9:00 PM

Post #28 of 32 (2790 views)
Re: [ChopperCharles] private and protected methods [In reply to] Can't Post

 

Quote
Okay, I've changed my code around, but there's still a problem:

unless ( (caller)[0]->isa( ref($self) ) ) {
$self->__SetLastError("Access to protected method denied.");
return -1;
}

This doesn't work when the caller is a subclass. If I have class B that inherits from class A, $self will be B, but caller will be A.



Since the subclass is inheriting from the parent, all the methods belong to the subclass, except those methods that are overridden. To access the parents versions, you must use SUPER. Even calling SUPER, as the TacoBell new method does, it still reports the caller as TacoBell.

When I ran a test on the script provided, I see that is the case:

# all the taco bell objects
NEW -> Self: TacoBell Caller: TacoBell
t = TacoBell->new();

Self: Caller: fooBar
__foo -> t->iAmfooBar() success.

Self: TacoBell Caller: main
__foo -> t->__foo("Charles") failed.

Self: TacoBell Caller: TacoBell (this is in the base class)
__foo -> t->burrito() success.


# the foobar objects
NEW -> Self: fooBar Caller: main
f = fooBar->new();

Self: fooBar Caller: main
__foo -> f->__foo("d'oh") failed.


Again, this is all in the perldoc object oriented tutorials.


(This post was edited by budman on Apr 3, 2012, 9:03 PM)


ChopperCharles
Novice

Apr 4, 2012, 8:38 AM

Post #29 of 32 (2774 views)
Re: [budman] private and protected methods [In reply to] Can't Post

So basically in order for inheritance and protected/private methods to work in a way that is not spaghetti left and right, the base class needs to know the name of all subclasses? That's hardly OO.

As for the other issue with the undef, I figured it out. Thanks.

I have been reading the OO for perl pages, btw.

Charles


budman
User

Apr 4, 2012, 9:13 PM

Post #30 of 32 (2760 views)
Re: [ChopperCharles] private and protected methods [In reply to] Can't Post

I don't think I follow on the base class needing to know its subclasses.

When TacoBell inherits from foobar, TacoBell extends foobar but its identity is still TacoBell. When you issue, use parent fooBar, this uses fooBar to load its methods into TacoBell's namespace/package, and then pushes fooBar onto @ISA. @ISA is used as a method lookup table, that sets a lookup precedence for method calling. When a method is requested, it searches TacoBell, in case of any overrides, and then fooBar.

Perl doesn't really support "Private" anything. Its all Public. We are using a hack to simulate Private functions. Python has the same issue, but decided to remove any methods from its lookup tables that begin with an underscore. However, this can be bypassed very easily, because even though it may appear to be private, its still public.

In Perl and Python, private is done by convention only. It's up to the programmer to respect this.

Now in Perl 6, there has been requests to add 'private' which will do exactly as you expect. So this may find it's way into Perl 5 as well.


As for Moose, there is an extension that does private and protected modes. But, they are still remain public.

http://lumberjaph.net/perl/2009/06/30/private-and-protected-methods-with-moose.html

Also, there are other ways, using trait and writer attribs in Moose to simulate private.

http://stackoverflow.com/questions/3996503/how-can-i-create-internal-private-moose-object-variables-attributes


(This post was edited by budman on Apr 4, 2012, 9:16 PM)


ChopperCharles
Novice

Apr 6, 2012, 12:17 PM

Post #31 of 32 (2747 views)
Re: [budman] private and protected methods [In reply to] Can't Post

Inside a method in fooBar:

Code
unless ( (caller)[0]->isa( ref($self) ) ) {...}

$self is fooBar, but caller is TacoBell. Even though caller inherits from fooBar, this will not work. So, inside fooBar I need:

Code
unless(index(caller[0], "fooBar") != -1 && index(caller[0], "TacoBell") != -1))


eg, if caller is fooBar or caller is tacoBell, we're good.

I don't want to rely on calling conventions. People often mess with things they shouldn't -- The goal here is to make it that much more difficult for someone to do something stupid.

If I could, I'd abandon perl altogether and write it in java or c++, but I'm extending an open source project and I am limited with what resources I can use. I can't even use a later version of perl.


budman
User

Apr 7, 2012, 7:56 AM

Post #32 of 32 (2738 views)
Re: [ChopperCharles] private and protected methods [In reply to] Can't Post

So you do not want this to be inherited or used by anything else.


Code
# create a class attribute 
my @myFriends = ( __PACKAGE__, "TacoBell" );

# change the unless statement in __foo to:
( my $object = (caller)[0] ) =~ s/.*:://;
unless ( grep { $object } @myFriends ) {
$m_LastError = "Access to private method denied. $object";
return -1;
}


Strange though, @ISA is pretty safe with inheritance.

Experienced Perl programmers have a lot of respect for each others logic and implementations. They know the limitations of the language and respect it and make it work. Just because objects can be accessed, or jail-breaked, or whatever, a majority if not all try to follow the best practice guidelines.


(This post was edited by budman on Apr 7, 2012, 8:05 AM)

First page Previous page 1 2 Next page Last page  View All
 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives