Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

code ref

by pg (Canon)
on Nov 10, 2002 at 00:24 UTC ( [id://211695]=perlquestion: print w/replies, xml ) Need Help??

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

I know how to use code ref in a way, for example, I can code,
$mw->Button(command => \&func1)->pack;
but 1) func1 is a function of a class, I will not be able to say
$mw->Button(command => \&$self->func1)->pack
, even not
$mw->Button(command => \&{$self->func1})->pack
, then what is the correct syntax? 2) more generic, how can you sepcify parameters for code ref? for example, I can not say,
$mw->Button(command => \&$func1($a))->pack
, then what is the correct syntax?

2002-11-10 Edit by Corion : Added CODE tags

Replies are listed 'Best First'.
Re: Declaring Code Reference With Parameters
by tadman (Prior) on Nov 10, 2002 at 01:05 UTC
    It probably stands to reason you should re-think your design, because this looks highly unusual.

    If you are determined to make it work, then this should fit the bill:
    $mw->Button(command => sub { $self->func1($a) })->pack();
    Instead of using a subroutine reference, this uses an anonymous subroutine which establishes the correct object and parameters. Note, however, that if $self changes, the subroutine is a closure and might not have the same value as you'd expect. Test carefully.
      I agree with you, have to rethink the design. The classes in Perl is somehow very awkward, and unusual. It is heavyly hacked, and does not really stands on all the good basics for OO programming.
        You should take a look at Damian Conway's book on OO programming in Perl - it's both a great introduction for newcomers to the language ( or OO ) and a valuable resource for advanced programmers. The book is dense with good design examples in OO Perl, some of them highly original. It might change your mind about Perl's OO features.

        I used to be a bit put off by the way Perl handles OO, but in time, you get used to it, and the inconvenience of various things is no longer an issue. You do, after all, have many conveniences to make up for these.

        In the end, you can get the job done just fine using Perl OO.
Re: code ref
by Aristotle (Chancellor) on Nov 10, 2002 at 14:58 UTC
    The problem here is a method is just a function - one that takes an extra first parameter. You could do something like $mw->Button(command => $self->can('func1'))->pack; but then the method will be called as a simple function without $self passed to it - nor of course any other parameters you might need. So if you want to stick by this route, you'll have to pass a closure, as tadman suggested: $mw->Button(command => sub { $self->func1($a, @_) })->pack;

    Keep in mind that OO in Perl is different from OO in other languages. One advantage that Perl offers is that it has closures; using them, you can emulate just about any behaviour you want to.

    I find OO in Perl is actually more flexible and powerful than OO in OO languages, with one painfully significant exception: no clean methodology to data inheritance.

    Makeshifts last the longest.

      no clean methodology to data inheritance.

      There is Tie::SecureHash for this purpose. But it is essentially a workaround for the issue you mention.

      --- demerphq
      my friends call me, usually because I'm late....

        Unfortunately, that solution suffers from the same fundamental problem: a derived class still has to know that $self is a hashref (in this case a blessed one, but that doesn't matter for our purposes). Without using Abigail's inside out objects trick, you cannot implement a subclass in Perl without knowing at least this one detail about the implementation of the superclass - what kind of thing $self is and how to store instance data in it.

        Makeshifts last the longest.

      no clean methodology to data inheritance

      Abigail-II's inside out objects trick is one solution to this. I'm still not sure if this is extremely elegant or an evil hack (or both :-)

      Bring on perl6 - hopefully it will make OO vaguely sane!

        It's an elegant hack. I was aware of it, but I don't like it: it relies on the stringified value of references which you're always advised to avoid. Yet it is necessary if you want to encapsulate fully, since there's simply no alternative way to do that in Perl 5.

        Makeshifts last the longest.

Three techniques for Tk button callbacks
by blssu (Pilgrim) on Nov 11, 2002 at 17:28 UTC

    Here are three examples of different ways to invoke a callback from a Tk button. The first is the simplest and "cleanest", but it uses the most memory. The second is simple and more memory efficient, but it is ugly. The third takes advantage of Tk's OO system and uses the least amount of memory, but it is inflexible if improperly designed.

    use strict; use Tk; use Tk::FooButton; my $MW = new MainWindow; # 1. callback using anonymous sub (also known as a # "closure") -- the arguments are embedded in # the closure. my $a_obj = new Foo (1); my $a = $MW->Button(-text => 'A', -command => sub { $a_obj->callback("pushed 'A'") } ) ->pack; # 2. callback using sub reference (looked up using # Perl's object-oriented "can" method) -- the # arguments are passed through the array reference. my $b_obj = new Foo (2); my $b = $MW->Button(-text => 'B', -command => [ $b_obj->can('callback'), $b_obj, "pushed 'B'" ] ) ->pack; # 3. callback using a custom (derived) Tk::Button -- # the arguments are stored as properties on the # button itself. my $c_obj = new Foo (3); my $c = $MW->FooButton(-text => 'C', -object => $c_obj, -message => "pushed 'C'") ->pack; MainLoop; # --------------------------------------------------------- package Foo; use strict; sub new { my ($class, $i) = @_; my $self = { -id => $i }; return bless($self, $class) } sub callback { my ($self, $message) = @_; print "$message using object #$self->{-id}\n"; } # --------------------------------------------------------- # SAVE THIS CODE AS "Tk/FooButton.pm" package Tk::FooButton; use strict; use base qw(Tk::Derived Tk::Button); Construct Tk::Widget 'FooButton'; sub Populate { my ($self, $args) = @_; $self->SUPER::Populate($args); $self->ConfigSpecs(-object => [ "PASSIVE", undef, undef, undef ], -message => [ "PASSIVE", undef, undef, undef ]) } sub invoke { my ($self) = @_; my $object = $self->cget(-object); my $message = $self->cget(-message); $object->callback($message) if ($object) } 1;

Re: code ref
by jackdied (Monk) on Nov 12, 2002 at 19:45 UTC
    You can do things like pass the name of the func instead of a code ref
    package Foo; sub whee { my $self = shift; print "$self says Wheee!\n"; } sub make_whee { my ($instance, $func) = @_; $instance->$func(); } make_whee(Foo->new(), "whee");
    You can also do things like pass in a ref to the class method, and just pass in self.
    $class_method_ref = \&Foo::whee; &$class_method_ref($foo_ob);
    But this will bite you badly later. The ISA tree for Foo will NOT be walked if you call methods in this fashion. Know the diference between these and you are all set.
    $foo_ob->bar("himom"); Foo::bar($foo_ob, "himom"); Foo->bar("himom");

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2024-03-29 00:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found