good chemistry is complicated,
and a little bit messy -LW
Re^3: RFC: Class::Proxy::MethodChainby Aristotle (Chancellor)
|on Feb 21, 2003 at 21:38 UTC||Need Help??|
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.