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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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.
| [reply] [Watch: Dir/Any] |
|
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.
| [reply] [Watch: Dir/Any] |
|
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.
| [reply] [Watch: Dir/Any] |
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. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
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....
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
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;
| [reply] [Watch: Dir/Any] [d/l] |
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");
| [reply] [Watch: Dir/Any] [d/l] [select] |