class methods

M

Matija Papec

I have situation where /class method/ can be called inside and outside of
package so I have to know when to throw away the first argument. I found
that

shift if $_[0] eq __PACKAGE__;

should work, but is there a better way to distinguish inside and outside
calls?
 
J

Jeff 'japhy' Pinyan

[posted & mailed]

I have situation where /class method/ can be called inside and outside of
package so I have to know when to throw away the first argument. I found
that

shift if $_[0] eq __PACKAGE__;

should work, but is there a better way to distinguish inside and outside
calls?

You could cheat with caller(). If the file of the caller of the function
is the same file the package is defined in, then you don't need to shift.
You could even just check if the PACKAGE the caller is in is the same as
the current package.

I assume you mean that you have code like so:

package Foo;

sub this {
...
}

sub that {
this(...);
}

and

package Bar;

Foo->this(...);

I would suggest that you NOT call a METHOD as a FUNCTION. But if you are
going to, then the caller() trick should be sufficient:

sub this {
shift @_ if (caller)[0] eq __PACKAGE__;
...
}
 
K

Kevin Michael Vail

Matija Papec said:
I have situation where /class method/ can be called inside and outside of
package so I have to know when to throw away the first argument. I found
that

shift if $_[0] eq __PACKAGE__;

should work, but is there a better way to distinguish inside and outside
calls?

What do you mean by inside and outside the package? Are you saying that
you want to call it as Foo->bar() from outside the package, and just as
bar() from within the package? I don't think you actually should do
that, because that makes it impossible for anyone to override bar() if
they create a subclass of your class.

If you can throw the first argument away, as what you've written above
suggests, then I would just always call it as a method. If you're
calling it from inside the package, just use the $self (or $this)
pointer you've got from the method you're in. That way inheritance
works properly.
 
J

James Willmore

Matija Papec said:
I have situation where /class method/ can be called inside and outside of
package so I have to know when to throw away the first argument. I found
that

shift if $_[0] eq __PACKAGE__;

should work, but is there a better way to distinguish inside and outside
calls?

==untested==
#get who's calling the method and the method's unnamed arguments
my ($caller, @args) = @_;
#return from the method unless the reference of the caller is equal
#to the PACKAGE name
return unless ref($caller) eq __PACKAGE__;

You may want to look over perltoot and perlbot.

HTH

Jim
 
I

Iain Truskett

* James Willmore said:
* Matija Papec said:
I have situation where /class method/ can be called inside and
outside of package so I have to know when to throw away the first
argument. I found that

shift if $_[0] eq __PACKAGE__;

should work, but is there a better way to distinguish inside and
outside calls?
==untested==
my ($caller, @args) = @_;
return unless ref($caller) eq __PACKAGE__;

This is a bad idea. When you subclass your module, your first argument
may end up being something very different from __PACKAGE__ (in
particular, it could be the __PACKAGE__ of a different package).

Personally, I'd not do this method at all. If it's a class method,
use it as a class method. If it's a function, use it as a function.
Don't do both. It just needlessly complicates the code and introduces
room for errors.



cheers,
 
T

Tore Aursand

I have situation where /class method/ can be called inside and outside of
package so I have to know when to throw away the first argument.

What do you mean, actually? Do you want to call the call a method's class
as a function, as in 'MyClass->Foo()'?

Seems like bad behaviour in my eyes, but then again I've never used
anything else than this syntax:

my $MyObject = MyClass->new();
$MyObject->foo();

Inside MyClass there's magic hand waving (well, not reall);

sub foo {
my $self = shift;
$self->bar();
}

sub bar {
my $self = shift;
# dada
}

Am I out of scope here? :)


--
Tore Aursand <[email protected]>

"You know the world is going crazy when the best rapper is white, the best
golfer is black, France is accusing US of arrogance and Germany doesn't
want to go to war."
 
M

Matija Papec

X-Ftn-To: Jeff 'japhy' Pinyan

Jeff 'japhy' Pinyan said:
I assume you mean that you have code like so:
package Foo;
sub this {
...
}
sub that {
this(...);
}
and
package Bar;
Foo->this(...);
Yes.

I would suggest that you NOT call a METHOD as a FUNCTION. But if you are

So what to do instead,

package Foo;
sub this {
...
}
sub that {
$self->this(...);
}
package Bar;
$object->this(...); #is Foo->this() also fine?

?
"And I vos head of Gestapo for ten | Michael Palin (as Heinrich Bimmler)
years. Ah! Five years! Nein! No! | in: The North Minehead Bye-Election
Oh. Was NOT head of Gestapo AT ALL!" | (Monty Python's Flying Circus)

Sure, and the crowd looked like plain English citizens. ;)
 
M

Matija Papec

X-Ftn-To: Kevin Michael Vail

Kevin Michael Vail said:
What do you mean by inside and outside the package? Are you saying that
you want to call it as Foo->bar() from outside the package, and just as
bar() from within the package?
Yes.
I don't think you actually should do
that, because that makes it impossible for anyone to override bar() if
they create a subclass of your class.

If you can throw the first argument away, as what you've written above
suggests, then I would just always call it as a method. If you're
calling it from inside the package, just use the $self (or $this)
pointer you've got from the method you're in. That way inheritance
works properly.

So basicaly it would be safest to call Foo()
$self->Foo(); within the package, and
SomeClass->Foo(); from other packages?
 
M

Matija Papec

X-Ftn-To: Tore Aursand

Tore Aursand said:
What do you mean, actually? Do you want to call the call a method's class
as a function, as in 'MyClass->Foo()'?
Yes.

Seems like bad behaviour in my eyes, but then again I've never used
anything else than this syntax:

my $MyObject = MyClass->new();
$MyObject->foo();

Even in cases when method isn't directly manipulating $MyObject but
impacting a whole class?
Inside MyClass there's magic hand waving (well, not reall);

sub foo {
my $self = shift;
$self->bar();
}

sub bar {
my $self = shift;
# dada
}

Am I out of scope here? :)

I think you're fine. :)
 
T

Tore Aursand

Even in cases when method isn't directly manipulating $MyObject but
impacting a whole class?

I'll be the first to admit that I'm not an OO guru; I've never been
teached "proper OO" (if there's such a thing) by a teacher (never attended
computer science at school), and I might not be familiar with the OO
terminology. I have, however, been programming "OO-style" for several
years (since the early 90's). And I've read Damian Conway's excellent
book about OO programming in Perl. :)

And:

There is no such thing as "manipulating a whole class", or - as you
describe it - impacting a whole class. You never work with _classes_.
You work with objects, which are _instances of classes_.

Therefore, IMO, one should avoid calling a class' method without going
through an instance of the class (even if this is possible in Perl).

If you're "manipulating a class directly", there is no need for objects
(or classes) in the first place. You would be dealing with "ordinary Perl
modules", which _will_ be troublesome in the long run.

Cutting from an other post from you:
So basicaly it would be safest to call Foo()
$self->Foo(); within the package [...]

Yes. If the method 'Foo()' is a member of the same _class_. Please be
specific when you're talking about packages/modules and/or classes. There
is a difference.
[...] and SomeClass->Foo(); from other packages?

No. You _should not_ call the class' method directly. You should rather,
as I've already pointed out, call the method on an instance (ie. an
object) of the class.
 
B

Bart Lateur

Matija said:
So basicaly it would be safest to call Foo()
$self->Foo(); within the package, and
SomeClass->Foo(); from other packages?

Eh! No. Always use Thisclass->Foo(), (or $obj->Foo()) from within this
or another package. Caution should be taken that when subclassing, the
package name might be something else than what is in __PACKAGE__. So
don't test for string-equality.
 
M

Matija Papec

I'll be the first to admit that I'm not an OO guru; I've never been
teached "proper OO" (if there's such a thing) by a teacher (never attended
computer science at school), and I might not be familiar with the OO
terminology. I have, however, been programming "OO-style" for several
years (since the early 90's). And I've read Damian Conway's excellent
book about OO programming in Perl. :)

And:
There is no such thing as "manipulating a whole class", or - as you
describe it - impacting a whole class. You never work with _classes_.
You work with objects, which are _instances of classes_.

I'm no OO expert neither but AFAIR, perl books talk about
object/instance methods and class methods. Class methods are afaik
called "static" in c++.
 
A

Anno Siegel

Tore Aursand said:
I'll be the first to admit that I'm not an OO guru; I've never been
teached "proper OO" (if there's such a thing) by a teacher (never attended
computer science at school), and I might not be familiar with the OO
terminology. I have, however, been programming "OO-style" for several
years (since the early 90's). And I've read Damian Conway's excellent
book about OO programming in Perl. :)

And:

There is no such thing as "manipulating a whole class", or - as you
describe it - impacting a whole class. You never work with _classes_.
You work with objects, which are _instances of classes_.

What makes you say that? Manipulation of the whole class is quite
possible and that's what class method calls are for. Typical examples
are language switching, making certain errors fatal, defining defaults
and lots more. Operations like these *should* be written as class
methods, because calling them through a specific object would be
misleading.

A limiting case is the constructor method (new()), which is generally
also a class method, though it does pertain to a specific object.
Therefore, IMO, one should avoid calling a class' method without going
through an instance of the class (even if this is possible in Perl).

Class methods are generally much rarer than object methods, but they
have their place.
If you're "manipulating a class directly", there is no need for objects
(or classes) in the first place.

What are you thinking of when you say "manipulating a class directly"?
The examples I gave above certainly make sense in an object oriented
setting.
You would be dealing with "ordinary Perl
modules", which _will_ be troublesome in the long run.

Cutting from an other post from you:
So basicaly it would be safest to call Foo()
$self->Foo(); within the package [...]

Yes. If the method 'Foo()' is a member of the same _class_. Please be
specific when you're talking about packages/modules and/or classes. There
is a difference.
[...] and SomeClass->Foo(); from other packages?

No. You _should not_ call the class' method directly. You should rather,
as I've already pointed out, call the method on an instance (ie. an
object) of the class.

A method should normally be either a class method or an object method,
and should be called accordingly. There is nothing wrong with calling
a class method through its package name, though this wouldn't depend on
from where it is called.

Calling a method as an ordinary sub is something else and should not
be done, because that would break inheritance.

Anno
 
T

Tore Aursand

What makes you say that?

I didn't, actually. It was the original poster who used the term
"impacting a whole class". I took it as he meant "manipulating a whole
class", which is a term I prefer.
Manipulation of the whole class is quite possible and that's what class
method calls are for.

I know that, but I still don't consider that as "manipulating a whole
class", whatever that _really_ means. :)

Your examples of using class methods are all fine, but they still define
the behaviour of the objects of the class (whether they _have been_
created or _will be_ created).

Please see my explanation in the context of the current thread; Instead
of using __PACKAGE__ to find out who's calling who, one should stick with
the good ol' fashioned OO style in calling methods in other classes. If
you don't, your design will break as soon as someone subclasses one of the
classes (as an example).
Class methods are generally much rarer than object methods, but they
have their place.
Indeed.

Calling a method as an ordinary sub is something else and should not be
done, because that would break inheritance.

Hmm. How many words did I use to say the same? :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top