The Advantages of Declarative Exporting

| 3 Comments

In Speeding Up My Test Suite by 25%, I lamented that writing modern Perl code often means using code which mangles the language at use time. Consider typical Moose code:

package MyApp::App::Role::HasMailer;
# ABSTRACT: role which provides other app roles with a mailer

use Modern::Perl;
use Moose::Role;

use MyApp::Mailer;

has 'mailer', is => 'ro', lazy_build => 1;

sub _build_mailer
{
    my $self        = shift;
    my $config      = do 'myapp_local.pl';
    my $mail_client = $config->{'Model::UserMail'}{mail_client};
    return MyApp::Mailer->new( $mail_client );
}

1;

... where functions such as has and with and extends look like declarations (such as my and sub), but are actually code to run.

The difference is important. A declaration that's part of the language's grammar need only be parsed to have its effects take place, while a statement or expression needs to run to take place.

This is, of course, why variable declarations makes lexical scoping trivial to understand for experienced Perl programmers, why binding closures to their lexical environments is easy in the simple cases, and why binding closures to their lexical environments when you use the STRING form of eval is so difficult.

As Moose hackers will tell you, Moose isn't a simple preprocessor you run over your code once to generate longer, uglier code without syntactic goodness. Instead, classes are built, not declared.

This is endemic to Moose, but it's not a characteristic specific to Modern Perl. It's inherent in Perl 5 itself, even the 1994 version. Perl 5 lets you run arbitrary code while parsing happens.

While you can gain tremendous flexibility with this approach (building up closures with partially applied arguments to export to caller namespaces), you can't serialize the resulting code as easily because you may have to run arbitrary code to restore your program in memory.

Put another way, Exporter is a library while it should be core language behavior.

In the simple case where a library wants to export a couple of symbols into the caller's namespace, say min and max from List::Util, why is there no simple syntax for marking those symbols as exportable in List::Util without having to run code (or worse yet, inherit from) Exporter?

If a declarative syntax existed—with language support or at least the broad consistency to allow for tool support—such that it were statically possible to determine the symbols exported from one package and imported into another package, precompilation would be easier. A module could have a static list of exports provided in a manifest of sorts. (A good optimizer could even decline to import unused code!)

I realize it isn't always possible to reduce all cases of exporting to a list of static symbols (nor is it desirable to remove that power), but at least 80% of the code I write would benefit from this. We'd also be able to have better tool support for the language; it would be easier to discover which symbols come from where, and we might even close the "You can't always tell which of two interpretations of a parse tree is valid in Perl 5 code thanks to import and BEGIN" gap a little further.

(... but then someone will ask why strict is a pragma and not core language behavior, especially after looking at its implementation, and then we'll all go to the paint store to pick out our favorite colors. See also "I didn't provide an example of this declarative syntax, so you can't argue about it in the comments.")

3 Comments

Larry punted on everything of this type by implementing "use" as instantly-executed but still vanilla Perl. I agree this was sweeping the complexity under someone else's rug. In fairness, when 5.000 was created, he had no way to know what would end up a good idea. I think we do now; it's a matter of tuition now, I think. Actually isn't there at least one exporter that uses attributes?

I've seen but not used Attribute::Exporter. I would have used it, but I needed to export partially applied closures in that project.

Thank goodness I appreciate irony.

Hi,Chromatic,seems the Declarative Exporting is amazing!Yes it is I want to ask:"why strict is a pragma and not core language behavior",I will see your refer post.

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide

Categories

Pages

About this Entry

This page contains a single entry by chromatic published on September 5, 2012 8:12 AM.

Speeding Up My Test Suite by 25% was the previous entry in this blog.

A Supposedly Terminating Loop I'll Never Write Again is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.


Powered by the Perl programming language

what is programming?