Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Reopen a class, add methods ?

by Rudif (Hermit)
on May 12, 2007 at 22:32 UTC ( #615124=perlquestion: print w/replies, xml ) Need Help??

Rudif has asked for the wisdom of the Perl Monks concerning the following question:

Learned monks,

Suppose that I want to adapt an existing class to my immediate needs, by adding some methods, right in my quick and not-too-dirty script.

I can see two ways, illustrated below, with Tk::HList::addrow() and updaterow().

Please comment on pros and cons, and on other possible ways to achieve this.

Rudif

#!/usr/bin/perl use strict; use Tk; use Tk::Label; use Tk::HList; sub Tk::HList::addrow { my ( $self, $row, $text ) = @_; $self->add($row); $self->itemCreate( $row, 0, -text => $text ); } package Tk::HList; sub updaterow { my ( $self, $row, $text ) = @_; $self->itemConfigure( $row, 0, -text => $text ); } package main; my @items; my $selectedrow = 0; my @text = qw ( AAA BBB CCC DDD EEE FFF ); my $mw = MainWindow->new(); my $frm1 = $mw->Frame()->pack( -side => 'top', -anchor => 'w' ); my $frm2 = $mw->Frame()->pack( -side => 'top', -anchor => 'w' ); my $but1 = $frm1->Button( -text => "reverse", -command => \&revers, -width => 20, )->pack( -side => 'left' ); my $label = $frm2->Label( -width => 5, -text => $selectedrow )->pack( -side => 'left' ); my $but2 = $frm2->Button( -text => "incr", -command => \&incr, -width => 15, )->pack( -side => 'left' ); my $hlist = $mw->HList( -itemtype => 'text', -height => 20, -separator => '/', -selectmode => 'single', -browsecmd => sub { $selectedrow = shift; $label->configure( -text => $selectedrow ); print "$selectedrow\n"; } )->pack; add(); MainLoop; sub add { foreach my $i ( 0 .. $#text ) { $hlist->addrow( $i, $text[$i] ); push @items, $i; } } sub refresh { foreach my $i ( 0 .. $#text ) { $hlist->updaterow( $i, $text[$i] ); } } sub incr { ++$text[$selectedrow]; refresh(); } sub revers { @text = reverse @text; refresh(); }

Replies are listed 'Best First'.
Re: Reopen a class, add methods ?
by ikegami (Patriarch) on May 13, 2007 at 02:03 UTC

    I recommend changing the package for the reasons I already gave.

    However, instead of

    package Tk::HList; sub updaterow { ... } package main;

    I'd use

    { package Tk::HList; sub updaterow { ... } }

    The package directive will only be effective until the end of the block, at which time the package will revert to what it was before the package directive was encountered.

    Hardcoding main will cause code to fail once ported to Apache::Registry, or if the code is copied/moved into a module.

      ikegami,

      Thank you (and others) for clarifications and guidance. A  package directive in a block works fine for me.

      Rudif

Re: Reopen a class, add methods ?
by friedo (Prior) on May 12, 2007 at 22:48 UTC

    Either way works fine, though I prefer not to have multiple packages in one file. But that's just a matter of style.

    However, it seems to me that defining a derived class would be a more sensible approach. If you don't want to make an actual module, you can define the class inline with your script.

    The following is untested but demonstrates the idea.

    #!/usr/bin/perl use strict; use Tk; use Tk::Label; use Tk::HList; package Rudif::Tk::HList; @Rudif::Tk::HList::ISA = ( 'Tk::HList' ); sub addrow { my ( $self, $row, $text ) = @_; $self->add($row); $self->itemCreate( $row, 0, -text => $text ); } sub updaterow { my ( $self, $row, $text ) = @_; $self->itemConfigure( $row, 0, -text => $text ); } package main; # your stuff here
      friedo,

      Originally I did experiment with inheritance, but I got into trouble with the Tk framework when I tried to instantiate my derived class. It seems that Tk classes are somehow different from typical perl classes.

      This is why I started looking for an alternative along the lines of 'reopen a class, add a method'.

      Rudif

Re: Reopen a class, add methods ?
by Joost (Canon) on May 12, 2007 at 22:50 UTC

      There's no real difference between the two solutions you provide,

      The difference is real enough. One of the variants has multiple non-obvious modes of failure.

      First of all, the difference is that sub Package::func { ... } compiles the function in the current package and places it in the target package, whereas { package Package; sub func { ... } } compiles the function in the target package. There are a few issues with using sub Package::func { ... }:

      It causes a problem when Carp is used. Carp will treat the function as belonging in the current package (main in this case), while it should treat it as being part of the target package to properly identify the caller.

      It causes a problem when the function imports symbols. The symbols will be placed in the current pacakge while they should be placed in the target package.

      It causes a problem when bless is used with one argument in the function. It will bless objects into the current package while they should be blessed into the target package.

      It causes __PACKAGE__ to be the name of the current package instead of the name of the target package.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://615124]
Approved by Joost
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (3)
As of 2023-02-01 11:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?