Object Oriented Perl : Query

Discussion in 'Perl Misc' started by Thens, Sep 6, 2004.

  1. Thens

    Thens Guest

    I have a base class called as Weapon and I have derived classes 'Gun'
    and 'RocketLauncher'. I need to instantiate Gun or RocketLauncher
    based on a parameter say distance from the target. If the distance is
    less than 20m I need a gun and if it is more I will need a
    RocketLauncher.

    This is my attempt at a Perl code that does this. Is this the right
    way to do this. Any pointers will be of help.

    #! /usr/local/bin/perl -w

    package Weapon;

    use strict;

    sub new {
    my ( $self ) = @_;
    my $class = ref($self) || $self;
    return bless { }, $class;
    }

    sub hitPoints {
    my ( $self ) = @_;
    return $self->{hitpoints};
    }

    sub fire {
    my ( $self, $target ) = @_;
    print "Destroyed the target !! ", $self->hitPoints;
    #$target->hurt($self->hitPoints);
    }

    package Gun;
    use strict;
    use base 'Weapon';

    sub new {
    my ( $self ) = @_;
    my $class = ref($self) || $self;
    $self = new Weapon();

    $self->{type} = 'GUN';
    $self->{hitpoints} = 10;

    return $self;
    }


    package RocketLauncher;
    use strict;
    use base 'Weapon';

    sub new {
    my ( $self ) = @_;
    my $class = ref($self) || $self;
    $self = new Weapon();

    $self->{type} = 'ROCKET';
    $self->{hitpoints} = 100;
    return $self;

    }

    1;


    --
    For this hour :
    Fools ignore complexity. Pragmatists suffer it. Some can avoid it.
    Geniuses remove it.
    Alan Perlis
     
    Thens, Sep 6, 2004
    #1
    1. Advertising

  2. Thens

    Anno Siegel Guest

    Thens <> wrote in comp.lang.perl.misc:
    >
    > I have a base class called as Weapon and I have derived classes 'Gun'
    > and 'RocketLauncher'. I need to instantiate Gun or RocketLauncher
    > based on a parameter say distance from the target. If the distance is
    > less than 20m I need a gun and if it is more I will need a
    > RocketLauncher.
    >
    > This is my attempt at a Perl code that does this. Is this the right
    > way to do this. Any pointers will be of help.


    Do what? I see no attempt to create one or the other depending on a
    parameter.

    I don't see any gross errors in the class setup. However, you should
    switch on warnings as a matter of course. Also, storing the weapon
    type in the object is not really necessary, since ref() can always tell
    you that.

    [code left in place for reference]

    Anno

    > #! /usr/local/bin/perl -w
    >
    > package Weapon;
    >
    > use strict;
    >
    > sub new {
    > my ( $self ) = @_;
    > my $class = ref($self) || $self;
    > return bless { }, $class;
    > }
    >
    > sub hitPoints {
    > my ( $self ) = @_;
    > return $self->{hitpoints};
    > }
    >
    > sub fire {
    > my ( $self, $target ) = @_;
    > print "Destroyed the target !! ", $self->hitPoints;
    > #$target->hurt($self->hitPoints);
    > }
    >
    > package Gun;
    > use strict;
    > use base 'Weapon';
    >
    > sub new {
    > my ( $self ) = @_;
    > my $class = ref($self) || $self;
    > $self = new Weapon();
    >
    > $self->{type} = 'GUN';
    > $self->{hitpoints} = 10;
    >
    > return $self;
    > }
    >
    >
    > package RocketLauncher;
    > use strict;
    > use base 'Weapon';
    >
    > sub new {
    > my ( $self ) = @_;
    > my $class = ref($self) || $self;
    > $self = new Weapon();
    >
    > $self->{type} = 'ROCKET';
    > $self->{hitpoints} = 100;
    > return $self;
    >
    > }
    >
    > 1;
    >
    >
    > --
    > For this hour :
    > Fools ignore complexity. Pragmatists suffer it. Some can avoid it.
    > Geniuses remove it.
    > Alan Perlis
     
    Anno Siegel, Sep 6, 2004
    #2
    1. Advertising

  3. Thens

    Ala Qumsieh Guest

    Thens wrote:

    > This is my attempt at a Perl code that does this. Is this the right
    > way to do this. Any pointers will be of help.


    There is a subtle mistake in your code. Have a look at the following
    pods for more info on Perl's OO mechanisms:

    perlboot
    perltoot
    perlobj

    Also, if you're serious about using Perl's OO, then reading Damian
    Conway's "Object Oriented Perl" is a must.

    > #! /usr/local/bin/perl -w
    >
    > package Weapon;
    >
    > use strict;
    >
    > sub new {
    > my ( $self ) = @_;
    > my $class = ref($self) || $self;
    > return bless { }, $class;
    > }
    >
    > sub hitPoints {
    > my ( $self ) = @_;
    > return $self->{hitpoints};
    > }
    >
    > sub fire {
    > my ( $self, $target ) = @_;
    > print "Destroyed the target !! ", $self->hitPoints;
    > #$target->hurt($self->hitPoints);
    > }
    >
    > package Gun;
    > use strict;
    > use base 'Weapon';
    >
    > sub new {
    > my ( $self ) = @_;
    > my $class = ref($self) || $self;
    > $self = new Weapon();


    Here, $self is an instance of the Weapon class. It is NOT a Gun object.
    If you add the following:

    print ref $self;

    You will get Weapon, not Gun. Depending on your application, that could
    not be a problem, but you're not getting true inheritance here. As long
    as your Gun package does not have any distinct methods of its own (or
    override any methods in Weapon, other than new()), then you are fine.
    But if you require true inheritance, then you need to make $self an
    instance of Gun. You do that by using SUPER:: like this:

    $self = $class->SUPER::new;

    This will look for the first new() method defined in the base class(es)
    of Gun and will invoke it with $class as the parameter. So, it will call
    the new() method in Weapon, which will return a hash ref blessed into
    the Gun class.

    > $self->{type} = 'GUN';
    > $self->{hitpoints} = 10;
    >
    > return $self;
    > }


    Ditto for RocketLauncher.

    --Ala
     
    Ala Qumsieh, Sep 6, 2004
    #3
  4. Thens

    Anno Siegel Guest

    Ala Qumsieh <> wrote in comp.lang.perl.misc:
    > Thens wrote:
    >
    > > This is my attempt at a Perl code that does this. Is this the right
    > > way to do this. Any pointers will be of help.

    >
    > There is a subtle mistake in your code. Have a look at the following


    [snippage]

    > > sub new {
    > > my ( $self ) = @_;
    > > my $class = ref($self) || $self;
    > > $self = new Weapon();

    >
    > Here, $self is an instance of the Weapon class. It is NOT a Gun object.


    Ah, I hadn't noticed when I certified this code as "free of gross errors"
    in another followup. This is a gross error in classes that do inheritance.

    Anno
     
    Anno Siegel, Sep 6, 2004
    #4
  5. (Randal L. Schwartz) wrote:

    > >>>>> "Thens" == Thens <> writes:

    >
    > Thens> sub new {
    > Thens> my ( $self ) = @_;
    > Thens> my $class = ref($self) || $self;
    > Thens> return bless { }, $class;
    > Thens> }
    >
    > Please see <http://www.stonehenge.com/merlyn/UnixReview/col52.html>
    > about why that ref($self) thing is bad.


    You recommend not using ref($self) because some people might guess
    incorrectly what new() does when it is used as an instance method.

    How about this: If people guess method behaviour rather than
    reading the docs their votes don't count. Allow $object->new(),
    document the behaviour, and expect people to read it.

    Peter

    --
    #!/local/bin/perl5 -wp -*- mode: cperl; coding: iso-8859-1; -*-
    # matlab comment stripper (strips comments from Matlab m-files)
    s/^((?:(?:[])}\w.]'+|[^'%])+|'[^'\n]*(?:''[^'\n]*)*')*).*/$1/x;
     
    Peter J. Acklam, Sep 8, 2004
    #5
  6. Thens

    Anno Siegel Guest

    Peter J. Acklam <> wrote in comp.lang.perl.misc:
    > (Randal L. Schwartz) wrote:
    >
    > > >>>>> "Thens" == Thens <> writes:

    > >
    > > Thens> sub new {
    > > Thens> my ( $self ) = @_;
    > > Thens> my $class = ref($self) || $self;
    > > Thens> return bless { }, $class;
    > > Thens> }
    > >
    > > Please see <http://www.stonehenge.com/merlyn/UnixReview/col52.html>
    > > about why that ref($self) thing is bad.

    >
    > You recommend not using ref($self) because some people might guess
    > incorrectly what new() does when it is used as an instance method.
    >
    > How about this: If people guess method behaviour rather than
    > reading the docs their votes don't count. Allow $object->new(),
    > document the behaviour, and expect people to read it.


    The point isn't so much that people fail to look up the definition,
    but that they (specifically, readers of code that uses the class)
    are forced to look it up. When you know what "Class->new(...)" does,
    you also know what "ref( $obj)->new(...)" does, but for the meaning
    of "$obj->new(...)" you must go to the documentation.

    The shortcut of calling ->new as an object method is inherently
    unclear. Unless there are massive advantages in allowing it (there
    aren't in most classes), I think it is better to leave it out. Its
    use as a matter of course smacks of cargo cult.

    Anno
     
    Anno Siegel, Sep 8, 2004
    #6
  7. Thens <> wrote in message news:<20040906175436.32d95abf@asiclindt001>...
    > I have a base class called as Weapon and I have derived classes 'Gun'
    > and 'RocketLauncher'. I need to instantiate Gun or RocketLauncher
    > based on a parameter say distance from the target. If the distance is
    > less than 20m I need a gun and if it is more I will need a
    > RocketLauncher.
    >
    > This is my attempt at a Perl code that does this. Is this the right
    > way to do this. Any pointers will be of help.
    >


    I added some comments and code to your code. There was a problem with
    the new methods in your child classes, they would have actually
    returned you the wrong class type. All of the new methods would have
    given you plain Weapon objects.
    You don't show any code about how to create a class depending on the
    conditions of distance as your statements above led me to belive the
    code would try to do. Was your question more along the lines of "Did
    I create me classes properly to use inheritance?"

    Or pehaps you were trying to find out how to have a class
    automatically change its type in the fire method? So when you invoke
    fire it checks the target distance and then calls fire on the proper
    weapon. Here is a class below
    which will act like a weapon, but delegate out to other weapons in the
    fire
    method depending on the distance.

    package SmartWeapon;
    use strict;
    use base 'Weapon';

    sub new {
    my $self = Weapon::new(@_);
    $self->{rocket} = RocketLauncher->new();
    $self->{gun} = Gun->new();
    }

    sub fire {
    my ($self, $target) = @_;
    if ($target->getDistance() < 20) {
    $self->{gun}->fire($target);
    }
    else {
    $self->{rocket}->fire($target);
    }
    }

    > #! /usr/local/bin/perl -w
    >
    > package Weapon;
    >
    > use strict;
    >
    > sub new {
    > my ( $self ) = @_;
    > my $class = ref($self) || $self;
    > return bless { }, $class;
    > }
    >
    > sub hitPoints {
    > my ( $self ) = @_;
    > return $self->{hitpoints};
    > }
    >
    > sub fire {
    > my ( $self, $target ) = @_;
    > print "Destroyed the target !! ", $self->hitPoints;
    > #$target->hurt($self->hitPoints);
    > }
    >
    > package Gun;
    > use strict;
    > use base 'Weapon';
    >
    > sub new {


    # you could allow your parent class to intialize everything
    # it needs to like this.
    my $self = Weapon::new(@_);

    # Don't need this stuff
    > # my ( $self ) = @_;
    > # my $class = ref($self) || $self;
    > # $self = new Weapon();
    >


    # now you can initialize the variables needed for the child class
    > $self->{type} = 'GUN';
    > $self->{hitpoints} = 10;
    >
    > return $self;
    > }
    >
    >
    > package RocketLauncher;
    > use strict;
    > use base 'Weapon';
    >
    > sub new {


    my $self = Weapon::new(@_);

    # don't need this stuff
    > #my ( $self ) = @_;
    > #my $class = ref($self) || $self;
    > #$self = new Weapon();
    >
    > $self->{type} = 'ROCKET';
    > $self->{hitpoints} = 100;
    > return $self;
    >
    > }
    >
    > 1;
     
    Bryan Castillo, Sep 9, 2004
    #7
  8. -berlin.de (Anno Siegel) wrote:

    > The shortcut of calling ->new as an object method is
    > inherently unclear. Unless there are massive advantages
    > in allowing it (there aren't in most classes), I think it
    > is better to leave it out. Its use as a matter of course
    > smacks of cargo cult.


    The "$class = ref($obj) || $obj;" construction is used many
    places in the Perl docs and the Perl standard modules, so
    its not strange that people choose to use it.

    Anyway, if it's use is disallowed an appropriate error
    message should be given. Maybe something like this:

    sub new {
    my $class = shift;
    croak "new(): not an instance method" if ref $class;
    ...
    }

    Peter
     
    Peter J. Acklam, Sep 9, 2004
    #8
  9. Thens

    Anno Siegel Guest

    Peter J. Acklam <> wrote in comp.lang.perl.misc:
    > -berlin.de (Anno Siegel) wrote:
    >
    > > The shortcut of calling ->new as an object method is
    > > inherently unclear. Unless there are massive advantages
    > > in allowing it (there aren't in most classes), I think it
    > > is better to leave it out. Its use as a matter of course
    > > smacks of cargo cult.

    >
    > The "$class = ref($obj) || $obj;" construction is used many
    > places in the Perl docs and the Perl standard modules, so


    Yes. Much to the regret of some of us. It's a pretty idiom,
    and it has been propagated by well-renowned people. (I'm
    tempted to say, people who should know better :)

    > its not strange that people choose to use it.


    No, it isn't. It is one of the harder design decisions *not* to
    do something on behalf of the user that seems to offer itself.

    If it is easy to do, and can as well be done outside the routine,
    think twice before doing it inside (and forcing it upon the user).
    You wouldn't sort a list result just because some users may want
    it sorted and others won't care. In this case, the performance
    penalty is obvious, so experienced programmers won't do it.

    The disadvantage of making ->new object-callable is "only" that
    the reader can't guess what exactly the object call does. That's
    less visible drawback, and so the idiom had a chance to spread.

    > Anyway, if it's use is disallowed an appropriate error
    > message should be given. Maybe something like this:
    >
    > sub new {
    > my $class = shift;
    > croak "new(): not an instance method" if ref $class;
    > ...
    > }


    Perhaps, but only because users may have come to expect it to be
    callable that way. Basically, ->new is a class method and the
    user has no business calling it through an object. If they
    do, they may as well deal with the consequences.

    Anno
     
    Anno Siegel, Sep 9, 2004
    #9
  10. -berlin.de (Anno Siegel) wrote:

    > Peter J. Acklam <> wrote:
    >
    > > The "$class = ref($obj) || $obj;" construction is used many
    > > places in the Perl docs and the Perl standard modules, so

    >
    > Yes. Much to the regret of some of us. It's a pretty idiom,
    > and it has been propagated by well-renowned people. (I'm
    > tempted to say, people who should know better :)


    Personally, I have let "$obj->new" be exactly the same as
    "ref($obj)->new" which wasn't even mentioned on Randal's page.

    > > Anyway, if it's use is disallowed an appropriate error message
    > > should be given. Maybe something like this:
    > >
    > > sub new {
    > > my $class = shift;
    > > croak "new(): not an instance method" if ref $class;
    > > ...
    > > }

    >
    > Perhaps, but only because users may have come to expect it to be
    > callable that way. Basically, ->new is a class method and the
    > user has no business calling it through an object. If they do,
    > they may as well deal with the consequences.


    Users all to often do things they have no business of doing. :)

    I think that *all* inappropriate or incorrect usage should display
    a descriptive error message.

    Peter

    --
    #!/local/bin/perl5 -wp -*- mode: cperl; coding: iso-8859-1; -*-
    # matlab comment stripper (strips comments from Matlab m-files)
    s/^((?:(?:[])}\w.]'+|[^'%])+|'[^'\n]*(?:''[^'\n]*)*')*).*/$1/x;
     
    Peter J. Acklam, Sep 9, 2004
    #10
  11. (Randal L. Schwartz) wrote:

    > *** post for FREE via your newsreader at post.newsfeed.com ***
    >
    > >>>>> "Peter" == Peter J Acklam <> writes:

    >
    > Peter> Personally, I have let "$obj->new" be exactly the same as
    > Peter> "ref($obj)->new" which wasn't even mentioned on Randal's page.
    >
    > Uh, wrong. Read closer. Especially that nearly last paragraph
    > from <http://www.stonehenge.com/merlyn/UnixReview/col52.html>:
    > [...]


    Sorry, you're absolutely right.

    Peter

    --
    #!/local/bin/perl5 -wp -*- mode: cperl; coding: iso-8859-1; -*-
    # matlab comment stripper (strips comments from Matlab m-files)
    s/^((?:(?:[])}\w.]'+|[^'%])+|'[^'\n]*(?:''[^'\n]*)*')*).*/$1/x;
     
    Peter J. Acklam, Sep 9, 2004
    #11
  12. Thens

    Anno Siegel Guest

    Peter J. Acklam <> wrote in comp.lang.perl.misc:
    > -berlin.de (Anno Siegel) wrote:
    >
    > > Peter J. Acklam <> wrote:
    > >
    > > > The "$class = ref($obj) || $obj;" construction is used many
    > > > places in the Perl docs and the Perl standard modules, so

    > >
    > > Yes. Much to the regret of some of us. It's a pretty idiom,
    > > and it has been propagated by well-renowned people. (I'm
    > > tempted to say, people who should know better :)

    >
    > Personally, I have let "$obj->new" be exactly the same as
    > "ref($obj)->new" which wasn't even mentioned on Randal's page.


    I'm not saying that it is fundamentally wrong to do that. But the
    decision to let a method (any method, not just ->new) be callable
    both ways is a design decision not to be taken lightly. There are
    methods that naturally work that way, most prominently those that
    ignore their first argument. Those are fair game, the user doesn't
    even have to know if they're class- or object methods. The call of
    a class method through an object still looks confusing because it
    looks like the individual object mattered while it doesn't.

    The ->new method is not of this kind (it *does* use its first argument),
    and in those cases there should be a solid reason for enabling the
    potentially misleading call. "It's easy to do and might come in handy"
    is not a solid reason.

    > > > Anyway, if it's use is disallowed an appropriate error message
    > > > should be given. Maybe something like this:
    > > >
    > > > sub new {
    > > > my $class = shift;
    > > > croak "new(): not an instance method" if ref $class;
    > > > ...
    > > > }

    > >
    > > Perhaps, but only because users may have come to expect it to be
    > > callable that way. Basically, ->new is a class method and the
    > > user has no business calling it through an object. If they do,
    > > they may as well deal with the consequences.

    >
    > Users all to often do things they have no business of doing. :)


    True.

    > I think that *all* inappropriate or incorrect usage should display
    > a descriptive error message.


    Well, that's an ideal, probably even an attainable ideal with the right
    technology, but in practice I tend to make a difference.

    Errors that I expect to be caused (and seen) by the end user must be
    caught and reported (in the end-user's terms, as far as possible).
    Those are mostly what would be classified as data- or input errors.

    Another type is usage errors. They happen through inappropriate
    usage of the class (module, software, library, whatever), and are
    only seen while an application of the class is written, not when
    it's debugged and running. Those can be caught by whatever internal
    mechanism catches them. So I wouldn't check the first parameter of
    a class method that isn't documented to be callable through an object
    but let Perl die on whatever the consequences are.

    Anno
     
    Anno Siegel, Sep 9, 2004
    #12
  13. Thens

    Anno Siegel Guest

    ? the Platypus {aka David Formosa} <> wrote in comp.lang.perl.misc:
    > (Peter J. Acklam) writes:
    >
    > [...]
    >
    > > Users all to often do things they have no business of doing. :)
    > >
    > > I think that *all* inappropriate or incorrect usage should display
    > > a descriptive error message.

    >
    > Isn't it the unix philosophy (and in turn perl's) to not forbid
    > inapproprate usage or "incorrect" usage for fear that it would also
    > prevent people from doing something brillent.


    Un-planned for, un-thought of usage is what shouldn't be prohibited.
    Inappropriate and incorrect usage (as in calling a class method through
    an object) isn't going to get you anywhere. No philosophy will change
    that.

    Anno
     
    Anno Siegel, Sep 28, 2004
    #13
    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. nus

    object-oriented perl

    nus, Dec 24, 2003, in forum: Perl
    Replies:
    0
    Views:
    528
  2. Replies:
    2
    Views:
    477
    Bruno Desthuilliers
    May 26, 2008
  3. rolo
    Replies:
    3
    Views:
    197
    Robert Klemme
    Apr 9, 2004
  4. Stefan
    Replies:
    4
    Views:
    159
    Mina Naguib
    Sep 16, 2003
  5. Replies:
    2
    Views:
    197
    Brian McCauley
    Dec 22, 2005
Loading...

Share This Page