OOP Tutorial

B

Brian McCauley

Leslie said:
Please forgive the cross-post

What cross-post? This thread is not cross-posted.
I hear comp.lang.perl is defunct.

Er yes, rather a long time ago.
Anyway, I have written yet another Perl OOP tutorial. If you are
interested, I'd appreciate your comments on it:

While not all OO systems have the concept of class I think it is worthy
of mention in the abstract part because so many do. Actually you do not
introduce the concept of class at all before you use it.

You could then mention that in most OO systems inheritance is between
classes not objects.

I'm glad to see you 'use strict' in your examples, in a contemporary
tutiorial you should 'use warnings' rather then utilize the -w switch.

You describe the scope of the package directive incorrectly.

The -> calls methods not subroutines. Actually they are the same thing
but to call a subroutine in a package (non-OO style) you just use a
namespace qualified call.

You mention the ability to manipuate package variables from outside way
too soon. Package variables as part of the package API should only be
use for things like DEBUG flags.

Your examples use package names with lower case names contrary to the
normal conventions.

Your example .pm files have #! lines - meaningless and confusing.

In your narrative you talk of using an implicit return in modules but in
your examples you use an explicit one (contrary to normal conventions).

(I stopped reading after 4/23 pages as I have to go now but I may take
another look later)
 
B

Brian McCauley

Leslie said:
Thank-you so much for the help!

To carry on...

Using the term 'our variable' to mean 'package variable' is slang.
There's nothing (IMHO) wrong with using it so long as when you introduce
the slang term you also proint out the proper term.

You use the term 'constructor' where you mean 'class method' in the
phrase 'when a method is not a constructor, the first parameter given to
it is not the class, but the blessed object'.

Calling a constuctor on an existing object is generally considered a BAD
THING. Having a constuctor that can be called on an existing object and
does something other than act as a (copy) constructor is an even worse
thing. [...] I now see that that you go on to talk about copy
constructors. IMNSHO you should not mention the idea that a constructor
could also be a instance method until you get to talking about copy
constructors.

print "address: ".$objectref->{address}."\n";

is more idiomatically

print "address: $objectref->{address}\n";

"If we don't want a copy constructor, we can make simple constructors
that can be called from both packages and objects like this"... but it's
bad form to do so, so don't do it.

Using the name super_animal of a subclass of animal is confusing.
(Since SUPER is also used to mean parent class).

The constuct base an rebless paradigm is usually the wrong one.

# 'Wrong'
$objref = animal->new ($name); # Construct base
return bless ($objref, $class);

# 'Right'
$objref = $class->SUPER::new($name)
return $objref;

The difference is that if animal::new internally calls any instance
methods that are overridden in super_animal then in the 'Wrong' example
animal::new will call the methods in animal:: rather than in
super_animal::. Usually this is the wrong thing. Occasionally it is
the right thing in which case the explict construct base and rebless
becomes the right thing.

You say of DESTROY 'If we define it, it will be called when an object
goes out of scope.' This is wrong - it is when there are nolonger any
references to the object. This may be when the variable holding the
last serviving reference goes out of scope, then again it may not.
 
J

John Bokma

Brian said:
Calling a constuctor on an existing object is generally considered a
BAD THING.

huh?

I remember having seen:

$a = $b->new;

here and there in books. I never use it, but I wouldn't call something a
bad thing in general.
Having a constuctor that can be called on an existing object and
does something other than act as a (copy) constructor is an even worse
thing. [...]

You mean:

$a = $b->new; and not copying all data from b to a? Depends of course on
what you do. I don't think something is a bad thing per se if it is used
in a way that is documented and not confusing.
Using the name super_animal of a subclass of animal is confusing.
(Since SUPER is also used to mean parent class).

In a tutorial you mean, agreed. In general it's often hard to model a
real world on OO. For example a menu as a specialisation of a window can
be confusion ( it's a window with less, instead of more :-D ).
 
L

Leslie Viljoen

Brian said:
Er yes, rather a long time ago.

I wonder if there is any way to get people to stop carrying the group
then. There are definitely still posts there and I posted there for a
while before discovering this group.
While not all OO systems have the concept of class I think it is worthy
of mention in the abstract part because so many do. Actually you do not
introduce the concept of class at all before you use it.
Ok, I have introduced that.
You could then mention that in most OO systems inheritance is between
classes not objects.
And in Perl it is also between classes right? I suppose its a
debatable point.
I'm glad to see you 'use strict' in your examples, in a contemporary
tutiorial you should 'use warnings' rather then utilize the -w switch.
OK, done.
You describe the scope of the package directive incorrectly.
Because package only functions within the enclosing block, right?
Ok, fixed that.
The -> calls methods not subroutines. Actually they are the same thing
but to call a subroutine in a package (non-OO style) you just use a
namespace qualified call.
This I am unsure about. I have tried calling package subroutines with
package::run() - but it doesn't seem to work. Can you give an example
of a working namespace qualified call?

Also, the -> works for packages where no object has been instantiated
with bless. So doesn't that mean it works in a non-OO environment too?
You mention the ability to manipuate package variables from outside way
too soon. Package variables as part of the package API should only be
use for things like DEBUG flags.
That's because I am starting with a non-OO perspective when introducing
packages for the first time. I guess I could put a note that using
package variables like that is not advisable?
Your examples use package names with lower case names contrary to the
normal conventions.
The examples in the Perl Programming book use camel caps I see. Is that
the convention? If so, does this convention work in windows? I suppose
Perl would ignore the filename case - I just don't have Active State
Perl here to test...
Your example .pm files have #! lines - meaningless and confusing.
True, will fix that.
In your narrative you talk of using an implicit return in modules but in
your examples you use an explicit one (contrary to normal conventions).
Ah yes, fixed that too.

Thanks again for the help!
Les
 
A

Alan J. Flavell

I wonder if there is any way to get people to stop carrying the
group then.

In practice, I suspect that would now be very hard; but if you want to
discuss the issue, you'd be better off on the news.admin.* hierarchy
regarding the necessary technical measures. I think there's general
agreement around here as to what the group's status is *meant* to be,
but on Usenet, that isn't the whole story. This could turn into a
massive thread about Usenet administration, policy and techniques,
with almost no relevance to the Perl language itself.

h t h
 
L

Leslie Viljoen

To carry on...

Using the term 'our variable' to mean 'package variable' is slang.
There's nothing (IMHO) wrong with using it so long as when you introduce
the slang term you also proint out the proper term.
Ok, I cleared that up.
You use the term 'constructor' where you mean 'class method' in the
phrase 'when a method is not a constructor, the first parameter given to
it is not the class, but the blessed object'.
Calling a constuctor on an existing object is generally considered a BAD
THING. Having a constuctor that can be called on an existing object and
does something other than act as a (copy) constructor is an even worse
thing. [...] I now see that that you go on to talk about copy
constructors. IMNSHO you should not mention the idea that a constructor
could also be a instance method until you get to talking about copy
constructors.

print "address: ".$objectref->{address}."\n";

is more idiomatically

print "address: $objectref->{address}\n";
Ok. I have had interpolation fail on me so I am by default wary of it
when I stick complicated things in strings.
"If we don't want a copy constructor, we can make simple constructors
that can be called from both packages and objects like this"... but it's
bad form to do so, so don't do it.
I actually took that example from "Programming Perl" on p294, -
"Dual-nature methods". Why is it bad form?
I will look into the whole copy constructor thing. I see John has
comments on that too.
Using the name super_animal of a subclass of animal is confusing. (Since
SUPER is also used to mean parent class).
I agree. At the risk of sounding corny, I have changed it to
mega_animal! SUPER is a bit of a funny choice for an ancestor though,
isn't it? Expecially since descendants are most often more "super" than
their parents.
The constuct base an rebless paradigm is usually the wrong one.

# 'Wrong'
$objref = animal->new ($name); # Construct base
return bless ($objref, $class);

# 'Right'
$objref = $class->SUPER::new($name)
return $objref;

The difference is that if animal::new internally calls any instance
methods that are overridden in super_animal then in the 'Wrong' example
animal::new will call the methods in animal:: rather than in
super_animal::. Usually this is the wrong thing. Occasionally it is
the right thing in which case the explict construct base and rebless
becomes the right thing.
Rebless? duh, I don't know that word! Its also not in my manual's pretty
comprehensive glossary - but I see Google knows it so I'll check out
what you are saying here.

Oh, I think I get it. But can you give more code examples?
You say of DESTROY 'If we define it, it will be called when an object
goes out of scope.' This is wrong - it is when there are nolonger any
references to the object. This may be when the variable holding the
last serviving reference goes out of scope, then again it may not.
Ok. I have been a bit more specific, I said:
If we define it, it will be called when there are no remaining
references to the object. That normally will happen when the program
ends or the block terminates – unless you have another reference to the
object stashed away somewhere.

Is that better?

Les
 
B

Brian McCauley

Leslie Viljoen wrote:

[ Attibution to Brian McCauley missing ]
I actually took that example from "Programming Perl" on p294, -
"Dual-nature methods".

Sometimes it's useful to have dual-nature methods but making all
methods, or just all constuctors dual nature by habit is bad.
Why is it bad form?

More code, less tight API for no gain.
SUPER is a bit of a funny choice for an ancestor though,
isn't it? Expecially since descendants are most often more "super" than
their parents.

Super means "above". Have you ever seen a family tree? These are
usually drawn the wrong way up for a real tree with the trunk at the top
and the branches at the bottom.
Rebless? duh, I don't know that word!

In English the prefix re- can be applied to any verb to mean "do again".
So to rebless is to bless again that which is already blessed.
Oh, I think I get it. But can you give more code examples?

When a class has a complicated constructor that constuctor may be split
into several parts that can be overridden separately in subclasses.

package Animal;

sub init_legs {
# Do stuff for initialising the legs of an animal
}

sub new {
my $class = shift;
my $self = bless {}, $class;
$self->init_legs;
$self;
}

package Specialized_Animal;

sub init_legs {
my $self = shift;
$self->SUPER::init_legs;
# Do additional stuff for initializing the legs of Specialized_Animal
}
Ok. I have been a bit more specific, I said:
If we define it, it will be called when there are no remaining
references to the object. That normally will happen when the program
ends or the block terminates – unless you have another reference to the
object stashed away somewhere.

Is that better?

Yes, much. But I still think 'the block' may be rather unclear.

I think you should hybidise this with the original.

'In the simplest case this will happen when the variable holding the
reference to the object goes out of scope.'

There are so many exceptions to this that there is no point mentioning
any of them unless you are really going to cover the subject properly.
After all it may not be that there's another reference to the object, it
may be there's another reference to the variable containing the
reference. The global destruction phase is a topic in itself. An you
can't properly talk about reference counting without also mentioning
circular references, weakened references and closures.
 
S

Sherm Pendley

Leslie said:
This I am unsure about. I have tried calling package subroutines with
package::run() - but it doesn't seem to work. Can you give an example
of a working namespace qualified call?

#!/usr/bin/perl

use warnings;
use strict;

package Foo;
sub say_something {
my ($msg) = @_;
print $msg;
}

package main;
Foo::say_something("Hello, world!\n");

This illustrates Brian's point: When you use :: syntax, you're making an
ordinary non-OO subroutine call. The name of the package is *not* passed as
the first argument.
Also, the -> works for packages where no object has been instantiated
with bless. So doesn't that mean it works in a non-OO environment too?

No, it just means you're calling a class method. In a class method, the
first argument is a string with the name of the class:

#!/usr/bin/perl

use warnings;
use strict;

package Foo;
sub say_something {
my ($class, $msg) = @_;
print "$msg from $class!\n";
}

package main;
Foo->say_something('Hello');

Once again, this highlights Brian's point: You can't call a method with ::,
nor can you call a non-OO sub with ->. If you try to, a different number of
arguments is passed than expected, with the expected arguments at the wrong
indices within @_.

sherm--
 
L

Leslie Viljoen

Hi Brian

Ok, looking at your rebless paradigm earlier:

# 'Wrong'
$objref = animal->new ($name); # Construct base
return bless ($objref, $class);

# 'Right'
$objref = $class->SUPER::new($name)
return $objref;


I have done this now, with the original animal class calling the run method.
I can see that it would be a good idea for the new mega_animal's new
to indirectly call its own run method - and this works fine, except that
mega_animal's run makes use of the num_eyes variable that is not yet
initialised:

(in mega_animal.pm)

sub run {
my $obj = shift;
my $name = $obj->{name};
print "$name running extremely quickly and looking around with ".
$obj->{num_eyes}." eyes in super_animal!\n";
}

sub new {
my $class_or_obj = shift;
my $class = ref ($class_or_obj) || $class_or_obj;

my ($name, $objref, $num_eyes);

if (!($name = shift)) { $name = "Blatsnork"; }

#$objref = animal->new ($name); # Old construct base - calls old
run method

# calls animal->new which calls run method above which uses unset vars!
$objref = $class->SUPER::new($name);

if (!($num_eyes = shift)) { $num_eyes = 2; }
print "Super animal new - eyes: $num_eyes\n";

$objref->{num_eyes} = $num_eyes;

return bless ($objref, $class);
}


So the problem is that I need to set a variable in my hashref, but the
new creates
that hashref so I can't do that. In this case would I have a system of
passing in
the hashref I want the constructor to use when it does the bless? Or
would this be
a case where I don't use SUPER?

I suppose this problem would only apply to a constructor since other
methods would
find our constructor had run and the proper variables had been created
by the time they run.
 
L

Leslie Viljoen

Rebless? duh, I don't know that word!
In English the prefix re- can be applied to any verb to mean "do again".
So to rebless is to bless again that which is already blessed.

And I had read plenty about blessing objects again.
I was reading reb-less, not re-bless - now I really feel a bit dim.

As in the Jack Handey deep thought:
Maybe in order to understand mankind, we have to look at the word
itself: "Mankind". Basically, it's made up of two separate words -
"mank" and "ind". What do these words mean ? It's a mystery, and that's
why so is mankind.
 
A

Anno Siegel

Leslie Viljoen said:
To carry on...
[...]

mega_animal! SUPER is a bit of a funny choice for an ancestor though,
isn't it? Expecially since descendants are most often more "super" than
their parents.

I agree, the subclass/superclass/isa terminology of OO doesn't match the
view of things of a programmer. In inheriting from a base class, we usually
don't mean to say that our objects are to be considered special cases of
the base class. We allow them to share some properties. @ISA would be
better named @MAY_IN_A_CERTAIN_LIGHT_LOOK_A_BIT_LIKE_A.

Anno
 
L

Leslie Viljoen

Anno said:
Leslie Viljoen said:
To carry on...

[...]


mega_animal! SUPER is a bit of a funny choice for an ancestor though,
isn't it? Expecially since descendants are most often more "super" than
their parents.


I agree, the subclass/superclass/isa terminology of OO doesn't match the
view of things of a programmer. In inheriting from a base class, we usually
don't mean to say that our objects are to be considered special cases of
the base class. We allow them to share some properties. @ISA would be
better named @MAY_IN_A_CERTAIN_LIGHT_LOOK_A_BIT_LIKE_A.

Anno
Or @COULD_BE_BETTER_COULD_BE_WORSE.
@WAS_A might actually be a good one.
 
A

Anno Siegel

Abigail said:
Brian McCauley ([email protected]) wrote on MMMMCXCVI September MCMXCIII in
<URL:news:[email protected]>:

[making ->new an object method]
Frankly, I fail to see the what the problem is. Noone seems to have a
problem with

$obj1 = $obj2 -> some_method_that_isnot_called_new;

But if "ref ($obj1) eq ref ($obj2)", the we have suddenly those irrational
fears and confusions happen, just like double quoted strings that don't
interpolate a variable, or a map in void context.

I never had a problem with

$obj1 = $obj2 -> method;

and I don't plan to make exceptions for methods that happen to return
objects from the same class.

That's absolutely fine if it makes sense. What I have a problem with
is a trend to make ->new object-callable just because you can. I often
see it in classes where there's no discernible reason why ->new should be
called through an object. There ought to be a visible or documented
advantage in making it so which is often missing.

Anno
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top