Beginning OO help

Discussion in 'Perl Misc' started by Arvin Portlock, Mar 27, 2007.

  1. 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 {};
     
    Arvin Portlock, Mar 27, 2007
    #1
    1. Advertising

  2. [ 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 <> wrote:
    > 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' $!";


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Mar 27, 2007
    #2
    1. Advertising

  3. Arvin Portlock

    Mumia W. Guest

    On 03/27/2007 04:14 PM, Arvin Portlock wrote:
    > 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
     
    Mumia W., Mar 28, 2007
    #3
  4. Arvin Portlock

    Uri Guttman Guest

    >>>>> "AP" == Arvin Portlock <> writes:

    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

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
     
    Uri Guttman, Mar 28, 2007
    #4
  5. Arvin Portlock

    Jamie Guest

    In <eubtv1$1j6f$>,
    Arvin Portlock <> mentions:
    >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
    --
    http://www.geniegate.com Custom web programming
    Perl * Java * UNIX User Management Solutions
     
    Jamie, Mar 28, 2007
    #5
  6. dans l'article eubtv1$1j6f$, Arvin Portlock à
    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::*
     
    john.swilting, Mar 28, 2007
    #6
  7. Jamie wrote:

    > 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
     
    Arvin Portlock, Mar 28, 2007
    #7
  8. Arvin Portlock

    Jamie Guest

    In <eueamb$5vq$>,
    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 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
    --
    http://www.geniegate.com Custom web programming
    Perl * Java * UNIX User Management Solutions
     
    Jamie, Mar 28, 2007
    #8
  9. 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?
     
    Arvin Portlock, Mar 29, 2007
    #9
  10. Abigail wrote:

    > Arvin Portlock () 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";
    }
     
    Arvin Portlock, Mar 29, 2007
    #10
  11. Arvin Portlock

    Dr.Ruud Guest

    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:
    >> Stick to CLASS -> method ().


    --
    Affijn, Ruud

    "Gewoon is een tijger."
     
    Dr.Ruud, Mar 29, 2007
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. newgenre
    Replies:
    1
    Views:
    320
    Curt_C [MVP]
    Apr 14, 2004
  2. bmlclemson08

    Beginning programmer... I need some help.

    bmlclemson08, Feb 5, 2006, in forum: C Programming
    Replies:
    8
    Views:
    299
    Michael Mair
    Feb 5, 2006
  3. hide2may

    [HELP] Beginning C++ Question

    hide2may, Jun 20, 2009, in forum: C++
    Replies:
    6
    Views:
    304
    James Kanze
    Jun 22, 2009
  4. Gawnsoft
    Replies:
    5
    Views:
    105
    Gawnsoft
    Sep 4, 2003
  5. Jesse B.
    Replies:
    9
    Views:
    261
    Jesse B.
    Mar 27, 2010
Loading...

Share This Page