Illusory

Whammo on 2002-04-11T03:50:16

"Sleight of hand and twist of fate
On a bed of nails, she makes me wait"
-- U2


I gave a presentation today. 15 Quick and Easy Perl Tricks to Amuse and Astound Your Friends (Assuming Your Friends Are Amused and Astounded by Quick and Eary Perl Tricks). It was further subtitled (Or, A Bunch of Sick and Queasy Perl Tricks to Confuse and Confound Your Friends (Assuming Your...., ah, you get the point.



Much of it was grandly inspired by Mark-Jason Dominus's various Wizard talks. (After all, there are only so many tricks in the world. But that's the real trick. Literally.)



Perl requires no real wizardry - no connection to the ethereal plane, no invocations that somehow summon behavior from beyond our mortal world. Except, perhaps, when trying to understand why anyone would do such tricks in the first place.



Nope, these are really just tricks, all descended from when the first caveman said, "Ook! Ag og oogag!" ("Look! I've got your nose!) Sleight of hand, classic misdirection, and simply hiding from the audience how it's all done.



In the end, we can pass on the tricks, although they are never the same. No, each trick is a variation on all the tricks that have come before, built upon the principles of simple magic.



Damian seems to create new magic out of the blue, while I was only able to regurgitate the same basic tricks after another, like a bad Reno lounge act. Typeglobs. Autoloading. Self introspection.



I did, however, get to present a Quick and Easy trick for providing Java-esque main methods for classes. (One of the few things I really like about Java.) I have a tremendous amount of "toolset" Perl code, all broken up in the traditional Unixy fashion of componts to be pipelined together.



But sometimes it can be damned inefficient to format data out of one Perl script, only to have to parse it coming in out of another. You can segregate the functional code into modules, but then how can you run them individually? In the end, you write Yet Another Script that provides a command line interface to the module, so you end up with twice the code and twice the number of files.



POD's intention was to keep the documentation as close to the functional code as possible. The DATA pseudo-handle's intention is to keep static data as close to the functional code as possible. Why can't we keep all the functional code as close together as possible? Here's the trick I came up with.



package MyPackage;

sub import { ... } sub new { ... } ... # Other "library" functions or methods

sub main { ... # Command line functionality }

&main unless exists $INC{__PACKAGE__ . '.pm};

1;


Create some linkage from the Perl libs to a bin directory, and it's an efficient way to do that sort of vectoring.



You can go a step further, because main() can always be called directly. Of course, it's going to expect to handle command line arguments, but guess what? @ARGV is localizable.



That allows the easy migration from system() to an inline Perl version. This all came up with attempting to use source filters to allow Perl to process Borne and Csh scripts. The transformations are rather trivial - if you don't count parsing - but you still don't gain much efficiency because all you're doing is spawning new processes anyway.



So the idea was to check for an identical Perl implemented toolset module - like Bin::Grep - that you could inline without having to know how to translate the tool's command line options. And then throw on B::Deparse on the backend.


Easier

Matts on 2002-04-12T10:28:36

Try that as:
main() unless caller;
I can't take credit for that. I think it was Gisle Aas that first thought of it.

Re:Easier

Whammo on 2002-04-12T12:01:13

Hmmm..... {ponder ponder ponder} I guess so. Thanks.