http://qs1969.pair.com?node_id=237243

I just wrote a module based on a concept that has been floating around in my head for a while. It looks fairly complete already, but is just an initial draft. I'd like some comments on what I should be wary of, what could be done better, things I might add or improve, and so on. Basically, any kind of feedback you come up with - I wanna hear it.

It follows the same goal as my quick multiple method calls against the same object (f.ex GUI programming) snippet - I suggest you take a quick look at it before reading on.

To reiterate, the idea is to achieve a smoother experience for those who're using classes with many setter methods that don't usually return anything meaningful or interesting. One such module is Gtk, the Perl binding of the GTK+ toolkit.

The idea is rather simple: instead of calling methods directly on the object in question, you call them on a proxy object wrapped around it. The proxy methods return $self after storing away the return value, so now you can chain calls to multiple methods.

Of course you can also retrieve the return value of the last method call of the chain.

Furthermore, to make an obvious concept a little more exciting, there are provisions for the case of methods returning aggregated objects, such as $file_dialog->ok_button->signal_connect(..);. In that case you can pass a coderef, which will be called with the results as its parameters. With an additional convenience function that assumes a single object reference as the returned value and wraps it into a proxy of its own, you can call another chain of methods on the return value of a method such as a ->ok_button in the above example.

Once I had my goals and desired approach straight, there was surprisingly little code to write:

#!/usr/bin/perl -w use strict; package Class::Proxy::MethodChain; use vars qw($AUTOLOAD); use constant OBJ => 0; use constant RET => 1; # handles method and constructor delegation sub AUTOLOAD { my $self = shift; $AUTOLOAD =~ s/^.*:://; if(ref $self) { $self->[RET] = [ $self->[OBJ]->$AUTOLOAD(@_) ]; $self; } else { bless [($self->$AUTOLOAD(@_))x2]; } } # wrap existing object sub wrap { my $self = shift; bless [(shift)x2]; } # get last return value or pass it to a callback without # breaking the chain sub ret_val { my $self = shift; if(@_) { my $callback = shift; local *_ = $self->[RET]; &$callback(@_); return $self; } else { return @{$self->[RET]}; } } # convenience function for when the return value is an objref sub ret_wrap { my $self = shift; my $wrapped = __PACKAGE__->wrap($self->[RET]->[0]); if(@_) { my $callback = shift; $callback->($wrapped); return $self; } else { return $wrapped; } } # allow calling methods with the same names as CPMC's sub call { $AUTOLOAD = shift; goto &AUTOLOAD; } sub DESTROY() {} 1;
Using this, the code from multiple method calls against the same object (f.ex GUI programming) reads a lot more naturally:
my $window = Gtk::Window ->Class::Proxy::MethodChain::new("toplevel") ->signal_connect(delete => sub { Gtk->main_quit }) ->set_title("Test") ->border_width(15) ->add(Gtk::Button ->Class::Proxy::MethodChain::new("Quit") ->signal_connect(clicked => sub { Gtk->main_quit }) ->show ) ->show;
I intend to put this on CPAN, so I'd really appreciate comments.

Makeshifts last the longest.