Beginning OO help

A

Arvin Portlock

I'm creating my very first object oriented module. I've read about
objects in so many perl books and online tutorials, and yet I still
can't get the hang of it. It's very frustrating. I've started by
designing a very simple class that has similar functionality to
what I eventually want to come up with, but not nearly as complex.
Just to get the hang of the basics before I get more complicated.
The class encapsulates an XML file. It has two attributes: the
file size and a linked list of the element names in the order they
are encountered in the file. Use it like this:

use Pete::MyFirstClass;

my $xmldoc = new Pete::MyFirstClass ('filename.xml');

print "The size of the document is ", $xmldoc->size, "\n";
print "Here is a list of the elements in the document:\n";

my $element = $xmldoc->elements;
while ($element) {
print $element->{name}, "\n";
$element = $element->{next};
}

__END__

Question 1: How do I turn {name} and {next} into accessor methods
rather than raw hash values?

Here's what I have so far:

package Pete::MyFirstClass;
require Exporter;
@ISA = qw(Exporter);
use strict 'vars';

sub new {
my ($self, $file) = @_;
my $size = -s $file;
my $elements = {};
my $last_element;
open (FILE, $file);
while (my $line = <FILE>) {
while ($line =~ /<([a-z0-9]+)[^<>]*>/g) {
my $name = $1;
my $tag = {};
$tag->{name} = $name;
if ($elements) {
$last_element->{next} = $tag;
$last_element = $tag;
} else {
$elements = $tag;
$last_element = $tag;
}
}
}
close (FILE);
return bless [$size, $elements];
}

sub size { return $_[0]->[0]; }
sub root { return $_[0]->[1]; }

__END__

## I'm guessing I'll need to create a new Element class with methods
## "next" and "name"? But I can't seem to get it to work right

package Elements;

sub new {
my $self = shift;
}

sub name {};
sub next {};
 
T

Tad McClellan

[ Please do not send steach Cc's. It is rude.
It is profoundly rude to do so when not using a real email address.
Please do not do that again.
]


Arvin Portlock said:
I'm creating my very first object oriented module. I've read about
objects in so many perl books


Some books are good, some are not so good.

Which books have you tried?

and online tutorials,


The overwhelming majority of those are not good.

and yet I still
can't get the hang of it.


Have you tried the tutorials that come with Perl itself?

perldoc -q object

Where can I learn about objectâ€oriented Perl programming?


open (FILE, $file);


You should always, yes *always*, check the return value from open():

open(FILE, $file) or die "could not open '$file' $!";
 
M

Mumia W.

I'm creating my very first object oriented module. I've read about
objects in so many perl books and online tutorials, and yet I still
can't get the hang of it.

Read "perldoc perltoot":
Start->Run->"perldoc perltoot"
It's very frustrating. I've started by
designing a very simple class that has similar functionality to
what I eventually want to come up with, but not nearly as complex.
Just to get the hang of the basics before I get more complicated.
The class encapsulates an XML file. It has two attributes: the
file size and a linked list of the element names in the order they
are encountered in the file. Use it like this:

use Pete::MyFirstClass;

my $xmldoc = new Pete::MyFirstClass ('filename.xml');

print "The size of the document is ", $xmldoc->size, "\n";
print "Here is a list of the elements in the document:\n";

my $element = $xmldoc->elements;
while ($element) {
print $element->{name}, "\n";
$element = $element->{next};
}

__END__

Question 1: How do I turn {name} and {next} into accessor methods
rather than raw hash values?

Read "perldoc perltoot"
Here's what I have so far:

package Pete::MyFirstClass;
require Exporter;

In this program, it probably doesn't make any difference, but it's
probably better usually to do "use Exporter;"

@ISA = qw(Exporter);
use strict 'vars';

sub new {
my ($self, $file) = @_;
my $size = -s $file;
my $elements = {};
my $last_element;
open (FILE, $file);
while (my $line = <FILE>) {
while ($line =~ /<([a-z0-9]+)[^<>]*>/g) { [...]

It's not a good idea to try to parse something as complicated as XML
with regular expressions. Use one of the XML parsing modules instead.

After you've finished reading "perldoc perltoot," you can get an
overview of the Perl documentation installed on your computer by reading
"perldoc perl"


HTH
 
U

Uri Guttman

AP> package Pete::MyFirstClass;
AP> require Exporter;
AP> @ISA = qw(Exporter);

why are you inheriting Exporter when you don't export anything? and in
pure OO modules you never export anything.

AP> use strict 'vars';

use strict ;

don't restrict only vars.


AP> while (my $line = <FILE>) {
AP> while ($line =~ /<([a-z0-9]+)[^<>]*>/g) {

parsing html with regexes is fraught with danger. use a parser.

AP> if ($elements) {
AP> $last_element->{next} = $tag;
AP> $last_element = $tag;
AP> } else {
AP> $elements = $tag;
AP> $last_element = $tag;
AP> }

you do the same assignment to $last_element in both clauses so factor
that outside the if/else.

AP> return bless [$size, $elements];

why are you using an array for an object? sure it works and can be a
trifle faster but it means you access object elements by number which is
not easily understood (see the pseudohash debacle for more on that).

as others have said you need to learn much more about OO perl. in fact
there is a book called object oriented perl and you should read
it. highly recommended by many perl hackers including myself
(disclaimer: i also was a tech editor of it). the perldocs on objects
and OO are also worth reading (in their ENTIRETY).

uri
 
J

Jamie

In said:
I'm creating my very first object oriented module. I've read about
objects in so many perl books and online tutorials, and yet I still
can't get the hang of it. It's very frustrating. I've started by
designing a very simple class that has similar functionality to
what I eventually want to come up with, but not nearly as complex.
Just to get the hang of the basics before I get more complicated.
The class encapsulates an XML file. It has two attributes: the
file size and a linked list of the element names in the order they
are encountered in the file. Use it like this:

I know what you mean about the frustrating part, when I learned it,
I was making "more" out of it than was really there.

No matter how they explained it, it wasn't till it hit me:

It's just a reference. (or pointer, if you perfer)
sub new {
my ($self, $file) = @_;
my $size = -s $file;
my $elements = {}; [snip]
close (FILE);
return bless [$size, $elements];
^^^^^^^^^^^^^^^^^

Woah! that's probably a bit much to start out with. It's valid, but
you might want to start with a plain old hash first, just to get
the feel for it.

I'll do some psuedo-code that might prove useful:

# Procedural, no package, no nothing.
sub constructor {
my(%data) = (
NAME => "John Henry"
);
return(\%data); # Return a non-magic, plain old reference.
}
sub get_name {
my($data_ref) = shift;
# Return the "instance variable" NAME. In other words: $data{NAME}
return( $data_ref->{NAME} );
}

# "Objects" w/out objects.
my $handle = construct();
my $name = get_name($handle);


All an object really is, is a reference. Even in other languages, it's just a
pointer. Big woop. (I use pointer/reference to mean more or less the same
thing)

The language may attach special meaning to the reference, inheritance, etc.. but
at the end of the day, it's still just a reference, not unlike a file handle or
a key that relates to a record in a table some place.

Ok, same thing, "objects", simple as possible:

package Foo;
sub constructor {
my($this) = shift;
# $this is the package name, usually: ref($this) || $this
my(%data) = (
NAME => "John Henry"
);
bless(\%data,$this); # Tell perl to set the "smoke & mirrors" bit
return($data);
}
sub get_name {
my($self) = shift;
return($self->{NAME}); # $data{NAME} by another name. A "fancy reference".
}
1;
package main;
my $object = Foo->constructor();
$object->get_name();

Or, same general idea (but don't do this):

my $object = &Foo::constructor('Foo');
&Foo::get_name($object);


There is more to it than this, of course. But if you "unlearn" the business of
class variables, instance variables and other techno-babble, the stuff about
@INC and packages will come natural and everything will be clear, leaving
you with a feeling of... "that's it ?!?!?"

$object is just a reference to %data with sugar on top.

There is no need to call Exporter or any of that stuff. "objects" in perl
are actually easier than procedural code.

Jamie
 
J

john.swilting

dans l'article [email protected], Arvin Portlock à
(e-mail address removed) a écrit le 27/03/07 23:14 :
I'm creating my very first object oriented module. I've read about
objects in so many perl books and online tutorials, and yet I still
can't get the hang of it. It's very frustrating. I've started by
designing a very simple class that has similar functionality to
what I eventually want to come up with, but not nearly as complex.
Just to get the hang of the basics before I get more complicated.
The class encapsulates an XML file. It has two attributes: the
file size and a linked list of the element names in the order they
are encountered in the file. Use it like this:

use Pete::MyFirstClass;

my $xmldoc = new Pete::MyFirstClass ('filename.xml');

print "The size of the document is ", $xmldoc->size, "\n";
print "Here is a list of the elements in the document:\n";

my $element = $xmldoc->elements;
while ($element) {
print $element->{name}, "\n";
$element = $element->{next};
}

__END__

Question 1: How do I turn {name} and {next} into accessor methods
rather than raw hash values?

Here's what I have so far:

package Pete::MyFirstClass;
require Exporter;
@ISA = qw(Exporter);
use strict 'vars';

sub new {
my ($self, $file) = @_;
my $size = -s $file;
my $elements = {};
my $last_element;
open (FILE, $file);
while (my $line = <FILE>) {
while ($line =~ /<([a-z0-9]+)[^<>]*>/g) {
my $name = $1;
my $tag = {};
$tag->{name} = $name;
if ($elements) {
$last_element->{next} = $tag;
$last_element = $tag;
} else {
$elements = $tag;
$last_element = $tag;
}
}
}
close (FILE);
return bless [$size, $elements];
}

sub size { return $_[0]->[0]; }
sub root { return $_[0]->[1]; }

__END__

## I'm guessing I'll need to create a new Element class with methods
## "next" and "name"? But I can't seem to get it to work right

package Elements;

sub new {
my $self = shift;
}

sub name {};
sub next {};
do not reinvent the whell me it does not answer me in all the cases
perl -e -mCPAN shell
install XML::*
 
A

Arvin Portlock

Jamie said:
It's just a reference. (or pointer, if you perfer)

I have seen the light. Seriously, I understand it all now.

It was useful for me to finally list explicitely the things I
understood and the things I didn't understand in all of the
documents I read and examples I had seen. Actually, the examples
were more useful (as in real OO distributed perl modules). The
problem with the documents was that they almost never looked
like real-world examples. For examples, the perl objects and
references book I don't think ever had an example that looked
like what one sees in the real world. What would have been
most useful to me would have been to *start* with the finished
examples then parse it apart and explain it.
return bless [$size, $elements];
^^^^^^^^^^^^^^^^^
Woah! that's probably a bit much to start out with. It's valid, but
you might want to start with a plain old hash first, just to get
the feel for it.

Gotcha, though now I understand this part and the underlying
slight gain in efficiency the docs talk about. Strangely, the
square brackets didn't really register as a simple array
reference before. I thought it was some magic having to do
with bless. Now I see, as you explained, that it's ALL just
references.

my $xmldoc = new Pete::MyFirstClass ('filename.xml');

$xmldoc isn't an object! It's nothing more than an array reference.
I get it now. It could as easily be a hash reference as well.
$xmldoc is nothing more than [$size, $elements], the two
variables I returned. Within new one could invoke the size method
like this as well: bless ([$size, $elements])->size; Not something
you'd ever want to do but it sure clears up what's going on
behind the scenes.

Another thing that confused me:

sub new {
....
return bless [$size, $elements];
}

sub size { return $_[0]->[0]; }

How does the size subroutine know what &new returned? It's
accessing array elements returned by new. How do the two
subroutines know about and communicate with each other?
Answer is of course they don't. They're just like any other
subroutines. They "communicate" via the $xmldoc "object."
That is $xmldoc->size calls the size subroutine and passes
to it, secretly, itself (which is a reference to an array).
All an object really is, is a reference. Even in other languages, it's
just a
pointer. Big woop. (I use pointer/reference to mean more or less the same
thing)

The language may attach special meaning to the reference, inheritance,
etc.. but
at the end of the day, it's still just a reference

Yup, something I've read in countless places but never sunk in until
now.
There is more to it than this, of course. But if you "unlearn" the
business of
class variables, instance variables and other techno-babble,

Unlearning is definitely necessary to learn this stuff. OO
really is just grafted onto perl. It's plain old references
used in clever ways with the help of bless.
There is no need to call Exporter or any of that stuff.

Thanks. I still don't understand Exporter but that will come.
No need to rush it for now. You've been very helpful. Now
it's time to start having some fun.

Arvin
 
J

Jamie

In said:
Unlearning is definitely necessary to learn this stuff. OO
really is just grafted onto perl. It's plain old references
used in clever ways with the help of bless.

Yep. :)

I actually really like it this way, it's shed a little light
on other languages (C++, Java, PHP) From what I've seen, all
of them do this same trick in one way or another.

Usually they do the equiv. of my $self = shift() for you and
then re-arrange "$name" to "$self->name" thus making it appear
as if something special is happening, with "this" having special
meaning.

It's all just pointers to pools of data with a whole lot of
techno-speak designed to trick you into thinking something earth
shattering has happened.

Perl just makes it plain, which I've come to appreciate.

(Who'd have thunk perl would be *more readable* LOL)

Jamie
 
A

Arvin Portlock

Jamie said:
In ,
Arvin Portlock mentions:



Yep. :)

I need help again! $obj = Package->new (args) works but I can't
get $obj = new Package (args) to work. The actual program is too
long to post here and I *tried* to reproduce it in a smaller simpler
program and failed.

Interestingly, if I simply declare the package name anywhere before
the current package then change it back, then the indirect method
works. In pseudo code, this does not work:

package MyPackage;

sub subname {
new OtherPackage (args);
}

package OtherPackage;

sub new {
print "OtherPackage here!\n";
}

But if I stick a bare package declaration at the top then the
indirect method works:

package OtherPackage;
package MyPackage;

sub subname {
new OtherPackage (args);
}

package OtherPackage;

sub new {
print "OtherPackage here!\n";
}

This reminds me very much of a forward declaration except it's a
package name!

Like I said, I cannot reproduce this problem in simpler code. But
can anyone tell me from the little I sketched above what might
be going on?
 
A

Arvin Portlock

Abigail said:
Arvin Portlock ([email protected]) wrote on MMMMCMLVII September MCMXCIII
in :
.. Jamie wrote:
..
.. > In ,
.. > Arvin Portlock mentions:
.. >
.. > >Unlearning is definitely necessary to learn this stuff. OO
.. > >really is just grafted onto perl. It's plain old references
.. > >used in clever ways with the help of bless.
.. >
.. >
.. > Yep. :)
..
.. I need help again! $obj = Package->new (args) works but I can't
.. get $obj = new Package (args) to work. The actual program is too
.. long to post here and I *tried* to reproduce it in a smaller simpler
.. program and failed.
..
.. Interestingly, if I simply declare the package name anywhere before
.. the current package then change it back, then the indirect method
.. works. In pseudo code, this does not work:
..
.. package MyPackage;
..
.. sub subname {
.. new OtherPackage (args);
.. }
..
.. package OtherPackage;
..
.. sub new {
.. print "OtherPackage here!\n";
.. }
..
.. But if I stick a bare package declaration at the top then the
.. indirect method works:
..
.. package OtherPackage;
.. package MyPackage;
..
.. sub subname {
.. new OtherPackage (args);
.. }
..
.. package OtherPackage;
..
.. sub new {
.. print "OtherPackage here!\n";
.. }
..
.. This reminds me very much of a forward declaration except it's a
.. package name!
..
.. Like I said, I cannot reproduce this problem in simpler code. But
.. can anyone tell me from the little I sketched above what might
.. be going on?


Yes.


This unexpected behavious is *exactly* why you shouldn't use the
indirect object method.

Stick to CLASS -> method ().



Abigail

I was able to reproduce the behavior in a small test program. It
also turns out I can make the indirect notation work by doing
this: new Package:: (args). I'm rereading about packages now. This
is behavior I've never encountered. Especially that weirdness about
the "forward declaration."

use Pete::MyFirstClass;
new Pete::MyFirstClass ('filename.xml');

# package Event; # Strangely, it works if I put this here!
package Pete::MyFirstClass;

sub new {
my ($self, $file) = @_;
my ($filename) = $file =~ /([^\/\\]+)$/;
&event_start;
}

sub event_start {
my ($element, $self) = @_;
# my $elt = new Event:: ($element); # This works
# my $elt = Event->new ($element); # This works
my $elt = new Event ($element); # This does not
}

package Event;

sub new {
print "New event encountered!\n";
}
 
D

Dr.Ruud

Arvin Portlock schreef:
I was able to reproduce the behavior in a small test program. It
also turns out I can make the indirect notation work by doing
this: new Package:: (args).

As Abigail ordered:
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top