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

Mar 28, 2012, 1:02 PM

Post #1 of 32 (9897 views)
private and protected methods Can't Post

I have an easy way of making methods private:


Code
package foobar; 

my $m_Self = undef;
my $m_LastError = "";

sub new {
my $type = @_;
$m_Self = {};
bless $m_Self, $type;
return $m_Self;
}
sub __foo { #private
if ($_[0] eq $m_Self) {
$m_LastError = "Access to private method denied.";
return -1;
}
my $name = shift(@_);
print "Hello $name.\n";
return 0;
}

sub run {#public, but can also be called from this package.
if ($_[0] eq $self) { shift(@_); }
my $name = shift(@_);
return __foo($name);
}

sub iAmFoobar { #public
return run("foobar");
}
1;


This works great, but now I want to make protected methods. Is there a way I can do this easily? I want to turn __foo into a protected method so that I can use it from a subclass... the only way I've been able to figure out how to call it is like this:


Code
package TacoBell; 
our @ISA = qw(foobar);

my $m_Self = undef;

sub new {
my ($type) = @_;
$m_Self = $type->SUPER::new();
bless $m_Self, $type;
return $m_Self;
}

sub burrito {
return $m_Self->SUPER::__foo("Charles");
}
1;


This doesn't work, for some reason when I call $m_Self->SUPER::__foo("Charles"), $self is added to the parameter list. I've tried this:


Code
 
if ($_[0] eq $self) {
my $me = shift;

if ($me->isa(__PACKAGE__) ){
print("is a package.\n");
} else { print "not a package.\n"; }


but "is a package" always prints, regardless of whether I call $tacobell->burrito() or $tacobell->__foo("Charles");.

How do I go about doing this?

Thanks.

Charles.


(This post was edited by ChopperCharles on Mar 28, 2012, 1:04 PM)


budman
User

Mar 28, 2012, 5:09 PM

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

 
I changed the way __foo and run handles its arg checking.


Code
 
package foobar;
use Carp;

sub new {
my $class = shift;
my $self = {};
bless ($self, $class);
return $self;
}

sub __foo { #private
my $name = shift;
if ( ref($name) ) {
my $self = $name;
# make it private
if ( ref($self) ne __PACKAGE__ ) {
confess("Access to private method denied.");
}
$name = shift;
}
print "Hello $name.\n";
return 0;
}

sub run {#public, but can also be called from this package.
my $name = shift;
if ( ref($name) ) {
my $self = $name;
$name = shift;
return $self->__foo($name);
}
else {
return __foo($name);
}
}

sub iAmFoobar { #public
return run("foobar");
}
1;


To inherit, you need to use the parent.
You can do:
use foobar;
use base foobar;
use parent foobar; # newer

Or look into Moose.pm:
extends 'foobar';

Edit: when you "use parent" it does a require on the module and pushes the module onto @ISA. No need to explicitly push @ISA.


Code
package TacoBell; 

use parent foobar;

sub new {
my $class = shift;
my $self = $class->SUPER::new();
#my $self = {};
#bless ($self, $class);
return $self;
}

sub burrito {
my $self = shift;
return $self->__foo("Charles");
# calling the inherited __foo from parent will fail
}

sub burrito2 {
my $self = shift;
# use this form if you need the super class's method
# to run before your overrides take place
my $x = $self->SUPER::__foo("Charles");
# override some stuff
return $x;
}

1;



Tests

Code
perl -MTacoBell -le '$t=TacoBell->new();$t->iAmFoobar' 
Hello foobar.

perl -MTacoBell -le '$t=TacoBell->new();$t->__foo("Chuck")'
Access to private method denied. at foobar.pm line 17.
foobar::__foo('TacoBell=HASH(0x605998)', 'Chuck') called at -e line 1

perl -Mfoobar -le '$t=foobar->new();$t->iAmFoobar'
Hello foobar.

perl -Mfoobar -le '$t=foobar->new();$t->__foo("Chuck")'
Hello Chuck.


perl -MTacoBell -le '$t=TacoBell->new();$t->burrito()'
Access to private method denied. at foobar.pm line 15.
foobar::__foo('TacoBell=HASH(0x605998)', 'Charles') called at TacoBell.pm line 17
TacoBell::burrito('TacoBell=HASH(0x605998)') called at -e line 1

perl -MTacoBell -e '$t=TacoBell->new();$t->burrito2()'
Access to private method denied. at foobar.pm line 15.
foobar::__foo('TacoBell=HASH(0x605a70)', 'Charles') called at TacoBell.pm line 26
TacoBell::burrito2('TacoBell=HASH(0x605a70)') called at -e line 1



Hope that helps


(This post was edited by budman on Mar 29, 2012, 10:00 AM)


ChopperCharles
Novice

Mar 29, 2012, 8:12 AM

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

I think I've got the concept, but I'm running into some down-right weirdness in my sample code. I keep getting "Can't locate object method iAmfooBar via package 1 at test1.pl line 15. It works from one class but not the other.

The actual files I'm using are attached.

note "base" and "parent" gave me errors, so I did not use them.

Charles.
Attachments: fooBar.pm (0.86 KB)
  TacoBell.pm (0.35 KB)
  test1.pl (0.47 KB)


ChopperCharles
Novice

Mar 29, 2012, 8:40 AM

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

Okay, right after I posted that I realized the problem was in foobar.pm, my $type = @_; should be my ($type) = @_;

That being said, the sample code doesn't work. $ret_code = $fb->__foo("d'oh"); should return an error, but it does not. Instead it prints the hash.

Charles.


budman
User

Mar 29, 2012, 9:47 AM

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

 
Test your return values in test1.pl

Success is 0, Fail is -1 - you were checking ret_code == 0


Code
$ret_code = $t->__foo("Charles"); 
print "RC: $ret_code\n";
if ($ret_code != 0) { print "t->__foo(\"Charles\") failed.\n"; }


Correct the " my $type = @_ " was actually getting the number of args and then using that number to bless the hash with. Changing it to " my ($type) = @_; " was correct.

That should work for you now.

What was the error for base and parent?

Did you use it as follows:

Code
use parent 'fooBar';


What version of perl are you using?


(This post was edited by budman on Mar 29, 2012, 9:54 AM)


ChopperCharles
Novice

Mar 29, 2012, 12:22 PM

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

Nope, my error codes are correct.

inside of test1.pl, calling __foo from ANY object should return nonzero (ie, it shouldn't work). If I get a return code of 0, that means it's not working properly. I should ONLY be able to call __foo() from inside TacoBell.pm or fooBar.pm. Nowhere else. test1.pl doesn't inherit from fooBar.pm, so it should not be able to call __foo().

In short, if the program prints those "failed" messages to the console, it didn't work.

It appears that I am using perl 5.1. (I cannot change this)

Charles.


ChopperCharles
Novice

Mar 29, 2012, 12:30 PM

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

Another question... how do I reference the private member variables I created in fooBar from TacoBell?

fooBar.pm has a member variable called $m_LastError, but I cannot find a way to set it from TacoBell.pm without first creating a setter method.

Charles.


budman
User

Mar 30, 2012, 7:12 AM

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

Let me clarify, the return code that you are getting in test1.pl is -1.
That is correct, however, the value you are testing for failure is 0, which is success. Your if statement is incorrect.

I understand what you want to do. The previous __foo I showed would only lock it down to the parent. To allow only the parent and any of its children to access it, you would need to check if the object isa fooBar.


Code
sub __foo { #private  
my $name = shift;
if (ref($name)) {
my $self = $name;
unless ( (caller)[0]->isa( ref($self) ) ) {
$m_LastError = "Access to private method denied.";
return -1;
}
$name = shift;
}
print "Hello $name.\n";
return 0;
}


Also, in test1.pl checking the retcodes needs to be fixed.


Code
my $ret_code = 0; 

print "TacoBell:\n";
my $t = TacoBell->new();
$ret_code = $t->iAmfooBar();
if ($ret_code) { print "t->iAmfooBar() failed.\n"; }
$ret_code = $t->__foo("Charles");
if ($ret_code) { print "t->__foo(\"Charles\") failed.\n"; }

print "fooBar:\n";
my $fb = fooBar->new();
$ret_code = $fb->iAmfooBar();
if ($ret_code) { print "f->iAmfooBar() failed.\n"; }
$ret_code = $fb->__foo("d'oh");
if ($ret_code) { print "f->__foo(\"d'oh\") failed.\n"; }




Code
Output: 
TacoBell:
Hello fooBar.
t->__foo("Charles") failed.
fooBar:
Hello fooBar.
f->__foo("d'oh") failed.


This shows that IAmfooBar is running the private __foo which is correct.
The fails occur when test1.pl tries to access them directly.

Other than this, I don't know of another way to enforce private subs. Maybe using a closure in fooBar.pm. Not sure.

Perl doesn't enforce private, everything is public. Private is done by convention, meaning its upto the programmer to KEEP it legit. Usually, when methods begin with underscores, it's a message to other programmers that this really should be treated as private and ignore it. Otherwise, there is no guarantee it will not break your app in the future.

You may want to look over the OO perldoc, they are really worth the time.
perlboot Perl OO tutorial for beginners
perltoot Perl OO tutorial, part 1
perltooc Perl OO tutorial, part 2
perlbot Perl OO tricks and examples

Otherwise, you may need to look into using Moose or other Class modules.

Perl 5.1 is quite old. I would ask to update to at least 5.12 if possible.


(This post was edited by budman on Mar 30, 2012, 7:22 AM)


budman
User

Mar 30, 2012, 7:58 AM

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

The variables $m_Self and $m_LastError would be known as class attributes / variables.

Using 'my' allows fooBar to hide these values from all other subclasses.
In other words, private.

In order to share these with the subclasses,
you need to use 'our' (no longer need to 'use vars', our does this now).


Code
in fooBar.pm: 
our $m_LastError;

in TacoBell.pm:
print $fooBar::m_LastError;


Variables are not inherited. Also, this becomes a maintenance nightmare.
This also breaks the rules of OOP, you are now treating it like a module.

You are getting into data storage now. Again, you should read the perl docs. They cover all of this.

If you want to keep them as class attributes,
then you need to add accessors so the subclasses can access them.


Code
in fooBar: 
sub getLastError {
return $m_LastError;
}

in TacoBell:
print $self->getLastError(),"\n";


This is the preferred method, because you are encapsulating the data, subclasses really shouldn't care about how its stored. Also, you are making your code very maintainable. Future programmers will love you.

There has been a recent change in creating accessors, instead of making a get and set for each attrib, we are now making dual purpose accessor/setor.


Code
sub lastError { 
my $self = shift;
if (@_) {
$self->{"_LAST_ERROR"} = shift;
}
return $self->{"_LAST_ERROR"};
}

in TacoBell:
print $self->lastError(); # get it
$self->lastError("something happened"); # set it


Try to stay away from using class variables/attributes if you can.
You really don't need $m_Self. If objects are blessed, they automatically pass theirs $self as the first arg.

The Error message would be better tied to the object not the class.
I usually limit class attributes to set defaults for the class.
Everything else is in the object. Also, for object vars in the class, I like to use uppercase and a leading underscore as well. Note, if you are using 'use strict', you must quote the hash key if it has a leading underscore.
ex: $self->{"_VAR"} or $self->{'_VAR'}

Lastly, using the class attribute for error message has a bug.
This may look like its working fine now. But.. add a second instance of TacoBell and you now have a very hard to track bug.

I changed fooBar.pm as follows:


Code
sub __foo { #private  
my $name = shift;
if (ref($name)) {
my $self = $name;
unless ( (caller)[0]->isa( ref($self) ) ) {
$self->lastError("Access to private method denied. $_[0]");
$m_LastError = "Access to private method denied. $_[0]";
return -1;
}
$name = shift;
if ( $name =~ /Burr/ ) {
$self->lastError("Weeeee Burrito!");
}
}
print "Hello $name.\n";
return 0;
}

# here is you class attribute accessor
sub GetLastError {
return $m_LastError;
}

# using the object data
sub lastError {
my $self = shift;
if (@_) {
$self->{"_LAST_ERROR"} = shift;
}
return $self->{"_LAST_ERROR"};
}



I added a second instance to test1.pl


Code
print "TacoBell:\n"; 
my $t = TacoBell->new();
$ret_code = $t->iAmfooBar();
if ($ret_code) { print "t->iAmfooBar() failed.\n"; }
$ret_code = $t->__foo("Charles");
if ($ret_code) { print "t->__foo(\"Charles\") failed.\n"; }
$ret_code = $t->burrito();
if ($ret_code) { print "t->burrito() failed.\n"; }
print $t->GetLastError();


print "\nTacoBell2:\n";
my $tb = TacoBell->new();
$ret_code = $tb->iAmfooBar();
if ($ret_code) { print "tb->iAmfooBar() failed.\n"; }
$ret_code = $tb->__foo("Peter");
if ($ret_code) { print "tb->__foo(\"Peter\") failed.\n"; }
print $t->GetLastError(),"\n";
print $t->lastError(),"\n";
print $tb->GetLastError(),"\n";
print $tb->lastError(),"\n";


Output:

Code
TacoBell2: 
Hello fooBar.
tb->__foo("Peter") failed.
Access to private method denied. Peter <--- WRONG
Weeeee Burrito!
Access to private method denied. Peter
Access to private method denied. Peter


The error code for the first instance was overwritten (one object bled into another). The class attribute exists for ALL instances. Remember, when dealing with objects, just because you used 'my' doesn't mean its limited to just that instance.


(This post was edited by budman on Mar 30, 2012, 8:27 AM)


ChopperCharles
Novice

Mar 30, 2012, 8:16 AM

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

Okay, I've changed the code to clarify the ret_codes to make them less confusing. At any rate, the code is attached, however, the output is incorrect.

When I run perl test1.pl, I should receive:

Hello fooBar.
Hello fooBar.

Instead, I get:

Hello fooBar.
Hello fooBar.
Hello fooBar=HASH(0x8ca8818)
Assertion failed.

Charles.


(This post was edited by ChopperCharles on Mar 30, 2012, 8:17 AM)
Attachments: test1.pl (0.58 KB)
  fooBar.pm (0.86 KB)
  TacoBell.pm (0.35 KB)


ChopperCharles
Novice

Mar 30, 2012, 8:23 AM

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

okay cool, switching to your isa() code seems to be working. I have tried several samples of isa I found on google, but couldn't get any of them to do what I wanted. Thanks!

Charles.


budman
User

Mar 30, 2012, 8:37 AM

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

I looked over the scripts you sent.
I tried the test1.pl with the assertions, and it ran as expected

Hello fooBar.
Hello fooBar.

Note: I updated my previous reply to show a bug with your $m_LastError attribute. If you switch it to use the lastError setter/accessor style you should be fine. The problem occurs when you add more than one instance of TacoBell.

Edit: I would really ditch $m_Self. Its another bug waiting to happen. It too is prone to multiple instances issue. Currently you only use it in new(), but anywhere else would cause you to access incorrect objects, as the reference is rewritten with each TacoBell->new() that is created.


(This post was edited by budman on Mar 30, 2012, 8:46 AM)


ChopperCharles
Novice

Mar 30, 2012, 8:45 AM

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

Maybe it has to do with different versions of perl, but that didn't work for me until I changed it to use the isa code you sent.

I don't understand the problem with lasterror, what are you saying?

Charles.


budman
User

Mar 30, 2012, 9:02 AM

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

 
The two vars in fooBar.pm,

Code
 my $m_Self; 
my $m_LastError;

are bugs waiting to happen.

If you create more than one instance of TacoBell, you now have multiple objects overwriting global class variables. This is very bad.

Bug 1: anytime TacoBell->new() is run to create a new instance, the global class variable $m_Self is ovewritten with the new object ref. If this variable $m_Self is used anywhere else in fooBar.pm (except in 'new') you will have objects calling other objects or worse other objects updating other objects data! BAD BUG!

Bug 2: $m_LastError is another global class variable. When ANY instance has an error, it is stored in the class. This means when you try to access the last error from instance #2, you are actually seeing the last instance that had an error - this could be instance #10, or #3, etc. Instance #2 loses it's last error message as soon as another error occurs anywhere. Thats a BAD BUG.

I know this is an example script, but these are very serious bugs that could lead to hours of debugging when its a real large production application. It's better to learn it now than later.

To fix those future bugs you would need to do the following:
1. eliminate $m_Self, and keep $self a lexical to new
2. use the object for data storage


Code
sub new { 
my ($type) = @_;
my $self = {};
bless($self, $type);
return $self;
}

sub lastError {
my $self = shift;
if (@_) {
$self->{"_LAST_ERROR"} = shift;
}
return $self->{"_LAST_ERROR"};
}



Does that help?


budman
User

Mar 30, 2012, 9:05 AM

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

Correct, the isa method is what you want to use. :)


ChopperCharles
Novice

Mar 30, 2012, 9:25 AM

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

So.... those are the equivalent of static variables in C++/java then? I don't want global variables, I want class member variables.

public class fooBar {
private String m_LastError = "";
};

is what I want.


ChopperCharles
Novice

Mar 30, 2012, 12:59 PM

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

The problem with your solution to moving $m_LastError into $m_Self is that if I call a method inside the pm, there is no $self passed. in foobar.pm, when the run method calls __foo, it doesn't pass a $self along with it.

This sounds like a huge can of worms, why would anyone design a language in this manner?

Charles.


budman
User

Mar 30, 2012, 2:05 PM

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

Perl and Python != Java and C++

Python does recognize some things like private functions when the name starts with an underscore. However, it is not FULLY protected. Perl leaves private vars and methods to convention.

To make a method work for either a passed ref, or a normal call,
check if the first arg is a ref.


Code
sub run { 
my $this = shift;
if ( ref($this) ) { return $this->__foo(+shift) }
else { return __foo($this) }
}


You can apply the same to __foo - check the first arg for ref,
and then proceed.


Code
sub __foo { 
my $this = shift;
if ( ref($this) ) {
unless ( (caller)[0]->isa( ref($this) ) ) {
$this->lastError("Access to private method denied.");
return -1;
}
}
my $name = ref($this) ? shift : $this;
print "Hello $name\n";
return 0;
}



Perl was never designed to be OO, it was band-aided to work with objects. Since objects are pretty much containers, this worked fine for most OOP concepts. Just like in C++, classes are pretty much structs with their inners kept private, unless you specify otherwise.


(This post was edited by budman on Mar 30, 2012, 2:22 PM)


budman
User

Mar 30, 2012, 2:15 PM

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

Static in the sense that the class is only loaded once.

Each instance does not create a new copy of the parent. So in a sense, these variables become static, but they are global to the class and subclasses via the accessors/setters.

If you wanted to track the number of instances loaded, you would use a class attribute, and increment it in new. Then create a sub DESTROY to decrement the attribute when objects are released.

Again, I think you should read the perldocs for OO and check out some comparisons, what you can and cannot do with Perl OOP. There are a lot of good examples in the perldocs that will answer a lot the questions you have and will have as you progress.

If you are looking for a good book on Perl OO - get "Object Oriented Perl" by D. Conway. He explains what each OO concept is and how it applies to Perl.


(This post was edited by budman on Mar 30, 2012, 2:17 PM)


ChopperCharles
Novice

Mar 30, 2012, 2:52 PM

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

Okay, I'm getting it now. There's another problem with the way that works though, in that if I don't have a $self passed in to a method, I cannot access properties of that class except through a function setter/getter. No direct access to $self->{dataItem}, even I have a getDataItem subroutine, bcause getDataItem is going to need a $self to get at that data. So in essence, I have to completely change the class I've been writing to work correctly... ah well, I learned something at least. (Err, not the foobar test classes I've been talking about, but rather the real code I'm working on :)

I'm assuming I'm not going to have any problems storing arrays or hashes in $self? (I know, big assumption)

Charles.


(This post was edited by ChopperCharles on Mar 30, 2012, 2:54 PM)


budman
User

Mar 30, 2012, 5:09 PM

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

 
I think your on the right track.

Storing data in hashes is quite easy. What's happens in the class, should stay in the class. Especially when it comes to data. This way in the future you can make changes to the base class, and not have to worry about fixing subclasses as long as you keep the accessors the same.

If you need to freeze and thaw the object, for faster load times, look into the storable module to help with that.


I played around with Moose to show how it would look (similar to Perl 6).


Code
	package fooBar; 
use Modern::Perl;
use Moose;

my $m_LastError = '';

after 'new' => sub { say "created instance from ".__PACKAGE__ };

has iAmFooBar => (
isa => 'Str',
is => 'ro',
lazy => 1,
default => sub { run("fooBar") },
);

has lastError => (
isa => 'Str',
is => 'rw',
default => '',
);
around lastError => sub {
my $orig = shift;
my $self = shift;
return blessed $self ? $self->$orig(@_) : $m_LastError ;
};


has priv_attrib => (
isa => 'Int',
is => 'ro',
writer => 'private_set_attrib',
default => sub { shift->default_value }
);

has run => (is => 'rw');
around 'run' => sub {
my $orig = shift;
my $self = shift;
return blessed $self ? $self->__foo(@_) : __foo($self,@_);
};


sub isa_friend {
my $class = shift;
my $this = shift;
if ( blessed $this ) {
unless ( $class->isa( ref($this) ) ) {
$this->lastError("Access to private method denied.");
return 0;
}
}
return 1;
}

sub default_value { return 0 }

sub __foo {
my $this = shift;
# private access only
my $class = (caller)[0];
return -1 unless isa_friend( $class, $this);
my $name = blessed $this ? shift : $this;
print "Hello $name\n";
my $error_occurred = 0; # to test modular code
if ( ! blessed $this && $error_occurred != 0 ) {
$m_LastError = "some error";
return $error_occurred;
}
else { $m_LastError = "" }
return 0;
}


1;



Code
	package TacoBell; 
use Modern::Perl;
use Moose;
extends 'fooBar';

after 'new' => sub { say "we can add stuff in ".__PACKAGE__ };

has burrito => (
is => 'ro',
isa => 'Str',
default => sub {
my $self = shift;
my $retcode = $self->__foo("Burrito!");
$self->lastError("problem with burrito") if $retcode;
return $retcode;
},
lazy => 1,
);


1;



Code
#!/usr/bin/perl 
use Modern::Perl;
use TacoBell;
my $tb = TacoBell->new();

say "private var is ".$tb->priv_attrib();
$tb->private_set_attrib(55);
say "private var is now ".$tb->priv_attrib();

# cause read-only error
#$tb->priv_attrib(10);

say "\ntb->Burrito:";
my $retcode = $tb->burrito();
say "RC: $retcode ", $tb->lastError();

say "\ntb->iAmFooBar:";
$retcode = $tb->iAmFooBar();
say "RC: $retcode ", $tb->lastError();

say "\ntb->__foo test";
$retcode = $tb->__foo("test");
say "RC: $retcode ", $tb->lastError();


say "\nFooBar:";
my $fb = fooBar->new();

say "\nfb->iAmFooBar:";
$retcode = $fb->iAmFooBar();
say "RC: $retcode ", $fb->lastError();

say "\nfb->__foo test";
$retcode = $fb->__foo("test");
say "RC: $retcode ", $fb->lastError();

# don't do this :)
#say "\nModular test for __foo test";
#$retcode = fooBar::__foo("test");
#say "RC: $retcode ", fooBar::lastError();



output:


Code
created instance from fooBar 
we can add stuff in TacoBell
private var is 0
private var is now 55

tb->Burrito:
Hello Burrito!
RC: 0

tb->iAmFooBar:
Hello fooBar
RC: 0

tb->__foo test
RC: -1 Access to private method denied.

FooBar:
created instance from fooBar

fb->iAmFooBar:
Hello fooBar
RC: 0

fb->__foo test
RC: -1 Access to private method denied.



(This post was edited by budman on Mar 30, 2012, 5:15 PM)


budman
User

Mar 30, 2012, 5:50 PM

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

 
Anytime we need access to the object, we make sure to call the method with $self-> this way Perl will pass the first arg for us. This is because $self was blessed. If you do use Data::Dumper; then run print Dumper($self) you will see how the hash is blessed.

$self->run("something");
$self->__foo(@_);

Now we have access to any of the object vars.

The $self->run( ) is the same as run($self, @_); (try not to do this)


(This post was edited by budman on Mar 30, 2012, 5:52 PM)


ChopperCharles
Novice

Apr 2, 2012, 11:47 AM

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

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.

Charles.


ChopperCharles
Novice

Apr 2, 2012, 3:24 PM

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

Another problem.... I'm using Class::Struct in my class. I used to have an array of these structs stored in my @m_StructArray, and accessed with a getter:

sub getStructArray { return @m_StructArray; }

I could easily access the array from outside the package,like this:


Code
my @strArray = obj->getStructArray(); 
print $strArray[0]->data . "\n";


Now I'm trying to store them in $self{_StructArray} instead, and no matter what I do I cannot seem to be able to access it in the same way. What is the syntax for storing and retrieving an array from inside $self? I've tried:

Code
sub getStructArray{  
my $self = shift;
return $self->{_StructArray};
}
sub getStructArray{
my $self = shift;
return @{$self->{_StructArray}};
}
sub getStructArray{
my $self = shift;
my @tmp= $self->{_StructArray};
return @tmp;
}

sub getStructArray{
my $self = shift;
my @tmp= @{$self->{_StructArray}};
return @tmp;
}

and maybe a few more. I'm just shooting in the dark trying different syntax and hoping something works, but so far all I've managed is a litany of unhelpful error messages.

There's something simple I'm missing, but I've spent the better half of the day searching google (and those sites you mentioned), and haven't found anything helpful.

Charles.


wickedxter
User

Apr 2, 2012, 6:20 PM

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

use datadumper module and dump the object ref. to find out its internals..


(This post was edited by wickedxter on Apr 2, 2012, 6:21 PM)

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