When you work with other people on a project, you either end up adopting
some of their coding styles or you end up not working with other people on that
project. When I've worked with teams of developers instead of on my own, I've
noticed that a lot of Perl code tends toward
ProjectName::Parent::Class::Hierarchy::Package::Name
unless very
carefully pruned with something like roles.
I found myself in a situation like that recently, and I noticed it because I
found myself typing class names like
ProjectName::Order::Family::Genus::Species::Subspecies
repeatedly.
The obsessive automator in my brain said "You should find a way to shorten
that". Occasionally I've written code like this:
package MyClass {
sub entity_class { 'ProjectName::Entity' }
sub container_class { 'ProjectName::Container' }
sub do_something
{
my $self = shift;
my $entity = $self->entity_class->new( ... );
my $container = $self->container_class->new( ... );
$container->add_entity( $entity );
...
}
}
This has a couple of benefits:
- It isolates the names of the dependent classes into a single, overridable (even injectable) place
- It's shorter
- It's unambiguous to parse, in that Perl will always understand the method call used to call the constructor as a method call
Recently I found myself thinking about Python instead. Even though Perl 5 and Python have essentially the same object system underneath (everything is a big bag of names and values and methods aren't all that special and there's essentially no distinction between a function and a method and did you know that everything you import into a class becomes part of its public interface?), the syntax differs. For example, Python doesn't have explicit constructor methods. To construct an object, call a function with the same name as the name of the class:
obj = Class();
That has the advantage that it's shorter and unambiguous. (It has the disadvantage that it looks like a function call, unless you hew to the convention that functions all start with lowercase names and class names all start with uppercase names.)
It's still shorter.
I found myself idly wondering if there were some way to make this available in Perl. (I know about aliased, but I haven't used it with something like namespace::autoclean, which is the obvious improvement.) How would that look?
I like the brevity and I like the unambiguity in parsing, but writing:
use aliased 'ProjectName::Order::Family::Genus::Species::Subspecies';
use namespace::autoclean;
my $species = Subspecies( ... );
... just feels wrong to me. It's a class method. Invoking a class method should look like invoking a method.
Way back in the day, the Perl 6 discussion turned to first-class classes, and we talked about anointing a new sigil. (My favorite was ¢.) I don't know how well this would work in Perl 5, but free yourself from the constraints of the actual for a moment and consider the possibilities. If we could refer to classes as first-class entities literally in source code:
- We could give them unambiguous aliases without confusing them for functions or methods
- Constructing an object via the class object would never be ambiguous to the parser
- Method lookup and concomitant optimizations would be easier
- We might be able to find more typeful optimizations
- Similar things (method invocation) would continue to look similar, while different things (object method invocation versus class method invocation) would look different
Of course, you could just as well argue that Perl 5 doesn't need another sigil.
I haven't convinced myself that I like this idea, but it does keep coming up. It has the feel of an intriguing idea, but I can't tell whether it's good, bad, or ugly. The right approach may instead be to flatten the hierarchy of classes in the program so that names are shorter overall... but even so, the idea of first-class classes has its benefits.
If you are looking at a new sigil, please look at non-US keyboards!
While the dollar symbol is present on a lot of national keyboards, the cent symbol is not. I'm working on a British-English keyboard and while $ is shift-4, the only way i've got for getting ยข is Alt+0162 on the numpad, very much less then convenient.
Actually with aliased, the syntax is:
The Subspecies(...) syntax can be achieved using Acme::Constructor::Pythonic.
Occasionallu I'll do:
{
package Foo::Class;
sub new { ... }
*Foo::Class = \&Foo::Class::new;
1;
}
Which then allows:
Foo::Class->(...);
as a constructor.
I haven't decided yet whether I like this enough to incorporate into any large projects; it feels pretty idiolectic.
No sigil needed! I was discussing this very topic with a co-worker a few weeks ago, then mentioned it in a blog comment, and tobyink++ posted this the next morning: https://metacpan.org/module/Acme::Constructor::Pythonic