From maine-pm at mail.pm.org Tue Jul 6 07:32:59 2004 From: maine-pm at mail.pm.org (maine-pm@mail.pm.org) Date: Mon Aug 2 21:32:11 2004 Subject: [Maine-pm] [Fwd: [Boston.pm-announce] Tech Meeting w/ Damian Conway, Tuesday, July 13] Message-ID: <40EA9BFB.4080002@open.com> An HTML attachment was scrubbed... URL: http://mail.pm.org/pipermail/maine-pm/attachments/20040706/f9e3480a/attachment.htm From maine-pm at mail.pm.org Tue Jul 6 13:32:09 2004 From: maine-pm at mail.pm.org (maine-pm@mail.pm.org) Date: Mon Aug 2 21:32:12 2004 Subject: [Maine-pm] [Fwd: [Boston.pm-announce] Tech Meeting w/ Damian Conway, Tuesday, July 13] In-Reply-To: <40EA9BFB.4080002@open.com> References: <40EA9BFB.4080002@open.com> Message-ID: <20040706142550.X52047@sasami.jurai.net> On Tue, 6 Jul 2004 maine-pm@mail.pm.org wrote: > > Looks like Damian Conway will be at the Boston PM meeting next > week. Thought you might like to know. It would have been awesome to see The Damian in action (everyone I know who has positively gush about the experience), but with so little notice AND having the meet on a weekday? Sadly, no can do. :( --k. From maine-pm at mail.pm.org Fri Jul 9 08:59:51 2004 From: maine-pm at mail.pm.org (maine-pm@mail.pm.org) Date: Mon Aug 2 21:32:12 2004 Subject: [Maine-pm] calling callbacks as object methods via hash lookup Message-ID: <3F29E984-D1B0-11D8-BF84-0003938E3BCC@inkfist.com> Hello out there, I was wondering if anyone has a better mousetrap for doing a hash lookup, a subroutine dereference and a method call all in the same statement. It looks easy in two statements, but the only way I can figure out to do it in one statement is with an extra reference/dereference: ++++++++++++++++++++++++++++++++++ #!/usr/bin/perl # callback_hash_test.pl # Purpose: test calling callbacks as object methods via hash lookup. # Use: command line use strict; package MyClass; sub new { my $self = { 'process' => \&my_process }; bless $self; return $self; } sub my_process { my ($self, $word) = @_; return "Your word is $word"; } package main; my $object = MyClass->new(); print $object->{'process'}, "\n"; # THE TWO-LINE METHOD my $process = $object->{'process'}; my $string = $object->$process("my_word"); print $string, "\n"; ++++++++++++++++++++++++++++++++++ This prints, as expected... CODE(0x8105d8) Your word is my_word The only way that I can figure out to do it in one statement is to reference and immediately dereference the code ref. This works: ++++++++++++++++++++++++++++++++++ my $string = $object->${\$object->{'process'}}("my_word"); ++++++++++++++++++++++++++++++++++ Is there a way to do this without the intervening reference/dereference? I suppose I could call it as a regular subroutine and pass the object as the first argument, but then it wouldn't be dispatched like a method should be, inheritance-wise. Here are some of my attempts and the resulting error messages. The first one seemed the most promising, but since the object is based on a hash I believe the statement was interpreted as a hash lookup. # my $string = $object->{$object->{'process'}}("my_word"); # Can't use string ("") as a subroutine ref while "strict refs" in use # I suppose $object->{'process'} is being stringified for what looks like a hash lookup. # my $string = $object->($object->{'process'})("my_word"); # Not a CODE reference # my $string = $object->$object->{'process'}("my_word"); # Can't locate object method "MyClass=HASH(0x801294)" via package "MyClass" # my $string = $object->&{$object->{'process'}}("my_word"); # syntax error ... near "->&" # my $string = $object->${$object->{'process'}}("my_word"); # Not a SCALAR reference # my $string = $object->{&$object->{'process'}}("my_word"); # Not a CODE reference Thanks, Bogart From maine-pm at mail.pm.org Mon Jul 12 10:33:11 2004 From: maine-pm at mail.pm.org (maine-pm@mail.pm.org) Date: Mon Aug 2 21:32:12 2004 Subject: [Maine-pm] calling callbacks as object methods via hash lookup Message-ID: <141385.1089646391716.JavaMail.root@wamui05.slb.atl.earthlink.net> I don't think I have an answer to your specific question, but I think I might solve the problem a little differently. Since I don't know precisely what you're trying to do, these suggestions may not help you -- it's just what came to mind after reading your email: First, I get nervous accessing object hash elements directly -- without some type of accessor method. So, if it were me, I'd try adding a method to the MyClass package like this: sub exec_process { my $self = $_[0]; return &{$self->{ 'process' }}; } You'd just need to make sure that $self->{ 'process' } was set to the right subroutine in your constructor (you mentioned needing to consider inheritance). You could try something like this: sub new { my $self = {}; bless $self; $self->{ 'process' } = $self->can('my_process'); return $self; } Then, in your 'main' package, you can use it like this: my $string = $object->exec_process('my_word'); Another idea I had was changing your constructor like this: sub new { no strict 'refs'; my $self = {}; bless $self; *{'MyClass::process'} = $self->can('my_process'); return $self; } And you can use it like this: my $string = $object->process('my_word'); Now, you automatically create the "process" method in the MyClass package and point it to the correct inherited instance of "my_process". Hope this is helpful Joe -----Original Message----- From: maine-pm@mail.pm.org Sent: Jul 9, 2004 9:59 AM To: maine-pm@mail.pm.org Subject: [Maine-pm] calling callbacks as object methods via hash lookup Hello out there, I was wondering if anyone has a better mousetrap for doing a hash lookup, a subroutine dereference and a method call all in the same statement. It looks easy in two statements, but the only way I can figure out to do it in one statement is with an extra reference/dereference: ++++++++++++++++++++++++++++++++++ #!/usr/bin/perl # callback_hash_test.pl # Purpose: test calling callbacks as object methods via hash lookup. # Use: command line use strict; package MyClass; sub new { my $self = { 'process' => \&my_process }; bless $self; return $self; } sub my_process { my ($self, $word) = @_; return "Your word is $word"; } package main; my $object = MyClass->new(); print $object->{'process'}, "\n"; # THE TWO-LINE METHOD my $process = $object->{'process'}; my $string = $object->$process("my_word"); print $string, "\n"; ++++++++++++++++++++++++++++++++++ This prints, as expected... CODE(0x8105d8) Your word is my_word The only way that I can figure out to do it in one statement is to reference and immediately dereference the code ref. This works: ++++++++++++++++++++++++++++++++++ my $string = $object->${\$object->{'process'}}("my_word"); ++++++++++++++++++++++++++++++++++ Is there a way to do this without the intervening reference/dereference? I suppose I could call it as a regular subroutine and pass the object as the first argument, but then it wouldn't be dispatched like a method should be, inheritance-wise. Here are some of my attempts and the resulting error messages. The first one seemed the most promising, but since the object is based on a hash I believe the statement was interpreted as a hash lookup. # my $string = $object->{$object->{'process'}}("my_word"); # Can't use string ("") as a subroutine ref while "strict refs" in use # I suppose $object->{'process'} is being stringified for what looks like a hash lookup. # my $string = $object->($object->{'process'})("my_word"); # Not a CODE reference # my $string = $object->$object->{'process'}("my_word"); # Can't locate object method "MyClass=HASH(0x801294)" via package "MyClass" # my $string = $object->&{$object->{'process'}}("my_word"); # syntax error ... near "->&" # my $string = $object->${$object->{'process'}}("my_word"); # Not a SCALAR reference # my $string = $object->{&$object->{'process'}}("my_word"); # Not a CODE reference Thanks, Bogart _______________________________________________ Maine-pm mailing list Maine-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/maine-pm From maine-pm at mail.pm.org Mon Jul 12 14:01:26 2004 From: maine-pm at mail.pm.org (maine-pm@mail.pm.org) Date: Mon Aug 2 21:32:12 2004 Subject: [Maine-pm] calling callbacks as object methods via hash lookup In-Reply-To: <141385.1089646391716.JavaMail.root@wamui05.slb.atl.earthlink.net> References: <141385.1089646391716.JavaMail.root@wamui05.slb.atl.earthlink.net> Message-ID: Joe, Thanks for the suggestions. I appreciate your review of the code and have enclosed some responses which may be of interest, depending on your workload and how easily amused you are by my awkward OO Perl code. At the very least, it has helped me to attempt to explain it. My overall objective was to write a logging module that would take a simple call like $my_log->log($var) and then dispatch a series of customizable callbacks from MyClass::log(). For example, _before() could output a heading, _each() could deal with the arguments themselves and _after() could follow up with a newline. I used the hash as a convenience for registering the callbacks, though in the production version they are only accessible through get/set methods as you suggested, or in the constructor. So, for example, if you said my $log = Log->new('before' => \&my_before_sub), it would override the default. Inheritance is handled by calling a _prototype() method inside the constructor which fetches the default callbacks from whatever package the object was blessed into. (This is adapted from Conway's book). sub new { my ($invocant, %args) = @_; my $obj = ref($invocant); # is invocant an object? my $class = $obj || $invocant; my $self = bless {}, $class; for my $prop ($self->_prototype()) { my ($arg) = ($prop =~ /^_(.*)/); if (exists $args{$arg}) { $self->{$prop} = $args{$arg}; } elsif ($obj) { $self->{$prop} = $obj->{$prop}; } else { $self->{$prop} = $self->_prototype($prop); } } return $self; } sub _prototype { my $self = shift; my %defaults = ( '_before_all' => \&_before_all, '_before_each' => \&_before_each, '_each' => \&_each, '_after_each' => \&_after_each, '_after_all' => \&_after_all, '_log_tag' => \&_log_tag, '_scalar' => \&_scalar, '_array' => \&_array, '_hash' => \&_hash, '_code' => \&_code, '_glob' => \&_glob, '_ref' => \&_ref, '_lvalue' => \&_lvalue, '_io::handle' => \&_io_handle, '_object' => \&_object, '_default' => \&_default, '_new_line' => "\n", '_indent' => "\t", '_line_char' => "^", '_rule_length' => 80, '_verbosity' => 3 ); return keys %defaults if wantarray; my $prop = shift; if (exists($defaults{$prop})) { return $defaults{$prop}; } } The convenience factor I was looking for would come into play as all these callbacks were calling each other at the upper reaches of the call stack. Here's an example. If an arrayref is passed in to the log method, it is recursively printed by calling '_each()' on each value. sub _array { my ($self, $ref, $indent, $v, $type, $address, $class) = @_; return unless ref($self); # object method only my $string; # OBJECT HEADING $string .= $self->${\$self->{'_object'}}($ref, $indent, $v, $type, $address, $class) if $class; # PREFIX if ($v) { $string .= $self->{'_new_line'} . $self->{'_indent'} x $indent . "["; $string .= " # $type at $address" if $v >= 5; $indent++; } # FIX for (@{$ref}) { $string .= $self->${\$self->{'_each'}}(\$_, $indent); } # POSTFIX if ($v) { $string .= $self->{'_new_line'} . $self->{'_indent'} x --$indent . "]"; $string .= $indent? "," : ";"; } return $string; } I like the idea of using a dispatcher method. Although it adds an additional call to the stack it still supports the convenience of invoking the callbacks with a single expression, as long as the name of the intended callback is passed in as an argument (which would then be used as a hash key). Also it would allow centralized error handling for misspellings and bad coderefs. Bogart