If you work on a large project, your code probably has a top-level namespace. If it's a large project, you probably have several secondary namespaces. I have seen this pattern time and again where you end up with:
MyProject
::Controller
::Model
::Report
::Role
::Template
::Utility
... and you get the idea. It's a little tedious typing out the full path to all of those modules when it's easy to assume what they are. Hold that thought for a moment.
One of the few things I like in Python better than Perl is that you create
an object by calling a constructor function. In other words, if you have an
IceCreamStore
class, you get an object by writing store =
IceCreamStore( ... );
. I don't like it because it's obvious
(Perl wins there) but I like it because it's shorter. (The other thing
in Python I like better than Perl is built in support for iterators.)
You can get a lot closer in Perl using aliased, but it doesn't give you constructor functions. Hold that thought.
One of the drawbacks of the Python "a class is just a hash table of
attributes and functionsmethods" design that Perl borrowed is
that any function imported into a class's namespace(to make your code shorter)
might be available as a method on objects of that class. Fortunately, you can
use something like namespace::autoclean
in Perl to unimport imported symbols after they've done their job. This works
because, once Perl's parser has seen a function, the optree it builds refers to
the proper function's storage location and the function's name association in
the namespace can go away without changing the optree at all. Hold that
thought.
While I was walking the dogs tonight, I figured out how to combine all of these things. This demo code works:
package MyDemo;
use classalias Class => qw( Foo Bar Baz );
sub get_all {
return Foo(), Bar(), Baz();
}
1;
... and you can call it with:
#!/usr/bin/env perl
use Modern::Perl;
use MyDemo;
say $_->number for MyDemo::get_all;
say MyDemo::Foo();
Yes, the names are silly and bad, but look at what the code does.
MyDemo
uses three other modules, Class::Foo
,
Class::Bar
, and Class::Baz
. Within
MyDemo
it can construct new instances of each of those classes by
calling functions named Foo()
, Bar()
, and
Baz()
.
Outside of MyDemo
, those functions do not exist.
The code is a little fragile because it's merely a proof of concept, but I'll post it in a few days.
Would I use this? Maybe. It needs more thought, but it only took a few minutes to write, which is a small investment for something that could save me lots of time in the future.