http://www.perlmonks.org?node_id=208518


in reply to multiple method calls against the same object (f.ex GUI programming)

If the method calls are set up properly, you can "chain" them, like:
(my $window = Gtk::Window->new("toplevel")) ->signal_connect(delete => sub { Gtk->exit(0); return }) ->set_title("Test") ->border_width(15) ->add($btn) ->show;
but this requires that each of these configurator calls returns $self as the last step, which is frequently the case, although beginners don't understand why to do this because they've not seen this pattern before. Even if it doesn't, I sometimes find myself simply chaining these calls using an alias:
my $window = Gtk::Window->new("toplevel"); for ($window) { $_->signal_connect(delete => sub { Gtk->exit(0); return }); $_->set_title("Test"); $_->border_width(15); $_->add($btn); $_->show; }
By not repeating $window repeatedly, you make it clear in the code that you are working on the same object every time. Also, it works well if you want to configure many objects similarly.

-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply.

Replies are listed 'Best First'.
Re: Re: multiple method calls against the same object (f.ex GUI programming)
by dada (Chaplain) on Oct 28, 2002 at 15:25 UTC
    ...but this requires that each of these configurator calls returns $self as the last step, which is frequently the case...

    just out of curiosity, but with this design in mind how would you return a value from a method call? even a simple boolean for success/failure. for example, how could you do something like:

    $window->set_title("Test") or die "Can't set title!\n";
    if you're always only returning $self?

    cheers,
    Aldo

    King of Laziness, Wizard of Impatience, Lord of Hubris

      Just use exceptions instead. Nothing wrong with wrapping a series of these things in an eval block to catch the exception.

      I prefer exceptions when an action will likely work 95% of the time or more. That way, the testing doesn't interfere with my examination of the control flow, and you get to do nice tricks like a "return $self" chain.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

Re^2: multiple method calls against the same object (f.ex GUI programming)
by Aristotle (Chancellor) on Oct 28, 2002 at 17:09 UTC

    I know about the first, but it wasn't possible here and also turns ugly when you have a multilevel call somewhere in that pile.

    I was actually thinking the second is as good as I can do in this case. What I didn't like about topicalizing with a for in that case is that for one, I still have to mention the object for every method call, although at least it's only $_ now. And worse yet, I still need a temporary variable for every widget, even when it's a widget I don't care about having access to later (scrollbars often fall in this category f.ex).

    By rearranging the program to use this snippet I managed to throw away about 4 out of 5 of my variables. That's more than a little win in clarity in my book.

    But thanks for the suggestions. :-)

    Makeshifts last the longest.

      And worse yet, I still need a temporary variable for every widget, even when it's a widget I don't care about having access to later (scrollbars often fall in this category f.ex).
      In that case, it gets even easier:
      for (Scrollbar->new) { $_->config1($param1); $_->config2($param2); $otherwidget->add($_); }
      Don't name anything you don't need to name!

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Sorry, one steap ahead of you again. :-) That breaks down when you need to add a nameless widget to another also nameless widget:
        for (HBox->new) { $_->config1($param1); $_->config2($param2); my $sb = Scrollbar->new; for ($sb) { $_->config1($param3); $_->config2($param4); } $_->add($sb); $window->add($_); }

        You need a temporary variable, although at least this one can be tightly scoped.

        It also mingles method calls against several different widgets into a single block, which makes it harder to see what gets added where when. Your proposal is ok on a smaller scale, but scales badly - if you nest several unnamed widgets, it gets messy quick.

        If you look at the tutorial at GtkPerl.org you'll see a really ugly style with lots of variable reuse and calls to different widgets interwoven in a single block. It made my head swim trying to read even the shorter example programs. configure_object was the result of several iterations of refactoring for readability.

        It took enough effort and was beneficial enough that I felt I had to share this.

        Update: Actually I suppose one can coerce the for approach into clean separation by adding some do to the mix:

        $window->add(do { my $hbox = HBox->new; for ($hbox) { $_->config1($param1); $_->config2($param2); $_->add(do { my $sb = Scrollbar->new; for ($sb) { $_->config1($param3); $_->config2($param4); } $sb; }); $hbox; });
        but that's quickly slipping into the realm of cumbersome. I really spent some serious time trying to get this whole deal to look reasonably readable, and no conventional tools would help, hence the snippet.

        Makeshifts last the longest.