Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re: Re: RFC: Class::Proxy::MethodChain

by sauoq (Abbot)
on Feb 21, 2003 at 20:30 UTC ( #237564=note: print w/ replies, xml ) Need Help??


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

I think it's easy to see that the latter syntax scales much better.

I don't see that. Even with your short example and, I think, a good understanding of your module, I find the "before" much easier to read than the "after." I'm having a hard time even determining whether the "after" version is correct or not. For instance, you are creating a closure within a method call within an assignment to the very variable your closure uses... does that work? What is the value of $file_dialog there?

The fact that you can't prevent collisions between your methods and those of the class you are proxying is a real problem. The best you can do is make the collisions less likely by requiring the user to deal with uglier method names. Breaking tradition and using underscores for public methods doesn't seem satisfactory. (Wouldn't you rather reinforce a tradition which makes good sense?)

It seems that all your module is really doing is providing some syntactic sugar to avoid some typing. You can make the "before" code cleaner without resorting to OO contortions. One way to clean it up a bit:

my $file_dialog = Gtk::FileSelection->new("File Selection Demo"); { my $b = $file_dialog->ok_button; $b->label("Load"); $b->relief("half"); $b->width(80); $b->height(50); $b->signal_connect(clicked => sub { print $file_dialog->get_filename(), "\n"; }); } { my $b = $file_dialog->cancel_button; $b->label("Exit"); $b->relief("half"); $b->width(80); $b->height(50); $b->signal_connect(clicked => sub { Gtk->main_quit }); } $file_dialog->set_filename("penguin.png"); $file_dialog->signal_connect(destroy => sub { Gtk->main_quit }); $file_dialog->show();
And you could do quite a bit better if you wrote a little utility function to handle the common button initialization.

In summary, I don't see a real benefit to using this module. I would avoid it as it doesn't seem to do much but provide a small syntactical shortcut, and that, IHMO, at the cost of clarity. For what it's worth, I can't think of a better way to do what you are attempting to do. (I just wouldn't attempt it at all.)

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


Comment on Re: Re: RFC: Class::Proxy::MethodChain
Select or Download Code
Re^3: RFC: Class::Proxy::MethodChain
by Aristotle (Chancellor) on Feb 21, 2003 at 21:38 UTC
    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.

      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
Node Status?
node history
Node Type: note [id://237564]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2014-11-22 16:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (123 votes), past polls