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

Re^3: RFC: Class::Proxy::MethodChain

by Aristotle (Chancellor)
on Feb 21, 2003 at 21:38 UTC ( [id://237577]=note: print w/replies, xml ) Need Help??


in reply to Re: Re: RFC: Class::Proxy::MethodChain
in thread RFC: Class::Proxy::MethodChain

For instance, you are creating a closure within a method call within an assignment to the very variable your closure uses... does that work?
Look carefully. The my declaration stands by itself at the top, in a separate statement.
What is the value of $file_dialog there?
That closure is a callback; nothing is called on $file_dialog at the time of its definition, just as one should expect from any other Perl closure. The value of $file_dialog will be a reference to the C::P::MC object wrapping a fileselect box widget, at the time the closure actually gets called.
all your module is really doing is providing some syntactic sugar to avoid some typing.
Correct, except for the "some" bit.
One way to clean it up a bit:

Frankly, yuck. I'd rather use the style from my before example than break all rules of indentation - at least with the before example's style, I can use Vim's "visual block" editing features (select a rectangular area, edit one line, same changes get applied to all the line fragments within the selected block) to make my life easier. And it doesn't break my autoindent.

Also, consider that very simple Gtk Perl app I've written. It's just a main window, a few buttons, a scrollable columnated list, a statusbar and a fileopen dialog - in other words, about the most minimal amount of GUI to do something useful. The code weighs in at well beyond two dozen widgets to set up - imagine how many variables that translates to. Now consider that the list of method calls against each is typically eight to a dozen lines and you get an idea for how much redundancy there is.

My sense of Once And Only Once nearly caused me seizures.

What makes it even more revolting is that the majority of these are actually going to be temporary variables, because once I've set up the corresponding widget it does its job on its own and I am no longer interested in it at all. (Scrollbars come to mind.)

merlyn addressed that with a topicalizing for, but then you have the problem that you must weave calls against different objects, which gets really messy real quick like. And it breaks down as soon as you nest more than one widget deep, such as a Button in a VBox in a Window, because you must weave calls against different objects in the same block, and "it"/$_ can only alias one object at a time.

There is no good way to get rid of the temporaries without writing a layer of my own syntactic sugar to insert between the main program and the widgets.

And you could do quite a bit better if you wrote a little utility function to handle the common button initialization.

(You realize that these are semicontrived examples. There is hardly any redundancy in method name and parameter set patterns in actual code.)

Did you take a look at multiple method calls against the same object (f.ex GUI programming)? It is indeed just a utility function, albeit admittedly not what you were talking about. The idea behind that snippet evolved into this module. That snippet does indeed work well; I get rid of nearly all temporaries and only need to mention the object of interest once. But using it is not a satisfactory solution in the long run - it introduces its very own (and very clumsy) syntax.

Consider on the other hand, as merlyn points out in reply to aforementioned node, that properly set up OO modules in Perl will allow chained method calls natively. Returning $self is what one should generally do wherever there's nothing else to do. Examples include Tk and Data::Dumper.

Gtk doesn't make the list.

Using C::P::MC, then, allows me to reclaim the benefit of established Perlisms.

GUI programming is verbose by definition. Setting up 5 properties each on 30 widgets is just going to take a lot of code whichever way you turn it. It helps if at least you don't have to type everything in quadruplicate (or more).

For all these reasons, I am not going to abandon this idea.

However, I am not pretending to have arrived at the best possible solution.

Breaking tradition and using underscores for public methods doesn't seem satisfactory.

It was more of an idle thought, and I agree with your point. Yes, the fact I can't prevent collisions is a real problem I'll have to get around.

One idea might be to move all functionality into AUTOLOAD; I could then add another "method name" like to_inner that serves to set an escape flag causing the next call to be passed down to the real object without examining the called method name. That would actually prevent collisions, albeit at the cost of verbose syntax when requesting so.

The likelyhood of that happening could be reduced by consolidating other functions (ret_wrap can be merged into ret_val and behaviour be selectable via a parameter flag) or using another unlikely prefix such as something that involves a double underscore; maybe p__foo where p is for proxy.

I'm inclined to do the latter, and actually considering to split functionality to more methods. Something like p__ret to get the return value, p__do for passing a closure, p__wrap for a wrapped aggregate object and p__wrapdo for a closure that takes a wrapped aggregate object seems to make sense.

Makeshifts last the longest.

Replies are listed 'Best First'.
Re: Re^3: RFC: Class::Proxy::MethodChain
by sauoq (Abbot) on Feb 24, 2003 at 22:15 UTC
    Look carefully.

    That's precisely my point. I'd rather not have to look carefully. Looking carefully should be required by tricky algorithms and obsfucations, not by a series of method calls.

    Correct, except for the "some" bit.

    I don't see that as a high goal. Typing is easy to begin with, and we can avoid most repetition in it by learning to drive our editors more expertly. Besides, it is much more important that code be easy to read than be easy to write. I agree, of course, that what is easy and what isn't mostly boils down to a matter of personal preference.

    I'm not so sure that personal preference alone should govern this case, though. I think this is kludgey at best, and I think I'm being pretty objective about that. You have written a class that does nothing but provide syntactical sugar. It doesn't do so transparently. In some cases it even seems to encourage mixing method calls from two different classes. Also, though unlikely to be a problem in most cases, the code is far from efficient.

    My sense of Once And Only Once nearly caused me seizures.

    I think this was a false application of that principle. How many times you type a variable name is irrelevant. If you find that your code is performing the same tasks repeatedly, in different places, then the principle applies. In that case, you consolidate the duplicated code and limit the number of pathways thereby reducing the chance for error. Your module actually increases the number of potential pathways through the code. For instance, someone might access a method through your proxy module or directly.

    If this is really an attempt to address something that bothers you with Gtk in particular, then maybe you should limit your module to being an auxillary module specifically for use with Gtk. That way, you could get around method name collisions through documentation. The inefficiency issue would probably never matter. And it would encourage the method chaining idiom in the very area you wished to see it. If it really caught on, maybe the Gtk authors would add support for it.

    -sauoq
    "My two cents aren't worth a dime.";
    

      I know it wasn't exactly a case of "once and only once", but that's the closest I could get to describe it. What I mean is that I found the previous code hard to read because of all the redundancy. There is a lot of repetition, but no so much that you could scan for patterns; reading the original-style code is downright painful.

      And no, while my immediate concern is Gtk, the thoughts behind this run far further.

      Ah, how I long for the beauty of saying something like

      given(Gtk::FileDialog->new()) { .ok_button.label("Load"); .cancel_button.label("Exit"); .connect_signal(destroy => sub { ... }); # ... }

      :-) That is really what I wanted to get out of this..

      Wait.. I feel an idea coming on.. The problem with the for approach is that you need to weave calls; which is the case because you can't access the topic past the block. If for where an expression that could return something, it would work. One way to get that done would be to abuse map:

      my $window = map { $_->signal_connect(delete => sub { Gtk->exit(0) }); $_->set_title("Test"); $_->border_width(15); $_->add(map { $_->signal_connect(clicked => sub { Gtk->exit(0) }); $_->show; $_ } Gtk::Button->new("Quit"); $_->show; } Gtk::Window->new("toplevel");
      Now I'm not really sure if I should think of this as really clever or really evil.. *grin*

      Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://237577]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (6)
As of 2024-04-10 21:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found