April 2010 Archives

Inside Perl 5.12

| 3 Comments

Perl 5.12 has just come out. A rejuvenated development process helps ensure a bright future for Perl as it enters its third decade of making easy things easy and hard things possible. Here's what you can expect when you upgrade to the latest release.

Release Schedule

The largest change in Perl 5.12 isn't code. It's the new release schedule. Perl 5 now has monthly development releases on the 20th of every month. Perl 5.13.0 is almost out, as of the time of writing. These monthly releases are snapshots of the development process. They represent points at which people interested in what will become Perl 5.14 can test against their most important code.

The current plan is to release Perl 5.14 in a year. Sometime around March, the release manager will put together release candidates and start the countdown for final testing and release blocking bugs. The process will repeat.

The Perl 5.12.x family will have several new releases in the next year as well, though they will have only a few changes. Jesse Vincent described the policy for what changes will go into Perl 5.12.x maintenance releases in a message to the Perl 5 Porters. 5.12.1 will come out in May 2010. It will contain fixes for bugs found in 5.12.0, but it will contain no new features or behaviors. 5.12.2 will follow in three months, and so on. It's not clear if 5.12.4 (February 2011) will be the final release of the 5.12.x family.

These plans are subject to change, but the monthly releases have gone well, and the release process for 5.12 had little controversy. It's likely the next year will proceed similarly.

Improved Package Version Syntax

In previous versions of Perl 5, individual packages set their version numbers by manipulating the package global variable $VERSION. There were few rules for what this variable contained or how to parse this version number, and toolchain modules such as ExtUtils::MakeMaker and Module::Build have to perform several contortions to parse them with any degree of accuracy. David Golden's Version Numbers Should Be Boring gives copious detail on how to do version numbers right, if you can't use 5.12.

An addition to the core version module enables a feature called "strict version numbers", where these numbers conform to a few guidelines. The most important rule is that version numbers must be standard numbers with one decimal point (1.23) or version strings (v1.234.5).

You may only use strict version numbers with the new package version syntax:

    package Perl::Improved 1.23;

    package Perl::Improved v1.23.45;

Internally, Perl will parse these the same way as it does:

    use Perl::Improved 1.23;

    use Perl::Improved v1.23.45;

... which is a benefit for consistency. As well, toolchain utilities can find and parse these version numbers with little effort, thanks in no small part to a canonical set of version number parsing regular expressions now found in version.

Sadly, there's currently no mechanism by which to add this syntax to 5.10, but in a couple of years this may be the preferred way of specifying version numbers in Perl 5.

Strictures by Default

Several CPAN modules enable features such as strict when you use them, including Moose, perl5i, Modern::Perl, Dancer, and Mojo. Perl 5.12 also enables strictures when it encounters use 5.012;, along with other new language syntax features such as the say and given/when keywords.

use 5.012 does not enable warnings.

The -E flag does enable new language features, but it does not enable strictures.

The -M5.012 flag does enable strictures and new language features.

Y2038 Safety

While Perl itself did not have a Y2K problem, many programs written in Perl made assumptions that produced apparent Y2K problems. Unfortunately, Perl's time handling relies on system libraries, and many of those systems exhaust their available capabilities when dealing with dates and times in the year 2038. (Developers who think they have decades to solve this problem should consider financial instruments such as 30-year mortgages.)

Perl 5.12 extends support for time and date handling in the core localtime and gmtime functions to manage dates beyond 2038 without overflow or truncation problems. Replacement libraries for earlier versions of Perl are available from the CPAN as Time::y2038.

Core Support for Language Mutation Extensions

Devel::Declare is the basis for a handful of CPAN distributions which add new features to Perl 5 without the drawbacks of source filters. signatures and MooseX::Declare are two prime examples; they simplify common tasks in a very Perlish way and demonstrate how a few syntactic additions can remove a lot of repetitive code.

Unlike source filters, they compose together well and don't interfere with external code.

Devel::Declare works by hijacking part of the Perl 5 parsing process. Though this has required poking in Perl's internals, Perl 5.12 includes a few APIs to make this behavior cleaner and better supported. In other words, it's not only okay for Devel::Declare to exist, but it's important that it exist and work and continue to work.

Some developers have discussed the idea of bringing Devel::Declare into the core in one form or another. This may or may not happen for Perl 5.14. Regardless, the process gives modules such as signatures and MooseX::Declare a further stability and support, and it provides opportunities for further syntax-bending extensions, some of which may enter the core themselves as new features.

Deprecation Warnings by Default

Perl 5 development makes a priority of supporting syntactic constructs found in older versions of Perl, even going as far as to deprecate but not remove some. As a minor compatibility change in Perl 5.12, deprecated features now give warnings when you use them, even if you haven't explicitly enabled deprecated warnings with use warnings 'deprecated';.

You may still disable deprecated warnings with no warnings 'deprecated';--they're still lexical warnings--but now these deprecations will be more obvious to developers who upgrade to and test their existing code against new releases of Perl 5.

Deprecations do not necessarily imply any timeframe for removal of the deprecated feature, except as otherwise expressed explicitly in the appropriate release delta. See perl5120delta for more details about specific deprecations in this release.

@INC Reorganized

Several of the core modules distributed with Perl 5 have dual lives on the CPAN. It's possible (and often worthwhile) to update them separately from the rest of Perl 5. If you do, Perl has to be able to find the updated versions instead of the core versions. When you compile Perl 5 itself, @INC contains a handful of default directories in which to look for modules. Some of these directories will contain core modules. Others contain modules you'll install later (likely through a CPAN client).

A reorganization of the order of these directories in the default @INC in Perl 5.12 makes Perl 5 prefer to load user-installed modules over core-supplied modules. This will make it easier to manage dual-lived modules, and should help distributions which package and redistribute Perl 5 to manage their installation paths appropriately. Unless you're a Perl 5 distributor, you should see no difference except for the lack of strange problems.

Deprecations

A handful of core modules are now deprecated: Class::ISA, Pod::Plainer, Switch, and Shell. They remain available from the CPAN, though consider using given/when (introduced in Perl 5.10.0) instead of Switch. There's no deprecation category quite strong enough to describe the recommendation against it.

The core has also included several libraries written in the Perl 4 era. They are now available from the CPAN in the Perl4::CoreLibs distribution. Though they are not quite deprecated yet, they will be in Perl 5.14. In almost every case, Perl 5 era replacements exist under active maintenance.

Unicode Improvements

As the Unicode standards change, so must Perl 5's Unicode handling. The biggest change in Perl 5.12 is an update to support the latest standards and definitions, specifically Unicode properties, property values, and regular expression matches using Unicode properties.

Miscellaneous

Many bugs have been fixed. Several performance improvements are present. More tests are available. Dual-lived modules have been updated. More documentation is available (including perlperf, a detailed discussion of profiling and optimizing Perl 5 programs). Some 200 people have changed 750,000 lines in more than 3,000 files.

Even with all of those changes, Perl 5 remains a vibrant, powerful programming language. Programs written a decade ago will still run with few, if any, necessary changes, and almost all of the CPAN is ready to run on it.

Yet development still continues. Perl 5.13.0 will come out on 20 April 2010, with all of the concomitant possibilities for improvements, bug fixes, and even more practical pragmatism. Perl 5.12.1 and 5.13.1 will follow next month, with more bugs fixed, documentation improved, core modules updated, and the language always a little bit nicer to use.

While Perl has a few heavy hitters in the web framework world (Catalyst, Jifty, CGI::App), sometimes they can seem like overkill. When writing a light web service or a high-end but not-as-complex website, you might want something smaller and simpler. This is where Dancer comes in.

Dancer is a web framework whose purpose is to let you get a website up and running within a minute, if not sooner. It started as a port of Ruby's Sinatra but has since took its own path.

Dancer supports Plack/PSGI from an early version and has a built-in scaffolding script to help you get up and running within seconds. It creates deployment scripts for you, includes a guide for deployment situations to help you configure your webserver (whether Perlbal, Apache, Lighttpd or anything else you might care to use) and has a default clean design to help you prototype your website faster.

Dancing

The best way to learn, understand, and fall in love with Dancer is to get on the dance floor:

    $ cpan Dancer # or cpanp, or cpanm
    $ dancer -a MyApp
    + ./MyApp
    + MyApp/views
    + MyApp/views/index.tt
    + MyApp/views/layouts
    + MyApp/views/layouts/main.tt
    + MyApp/environments
    + MyApp/environments/development.yml
    + MyApp/environments/production.yml
    + MyApp/config.yml
    + MyApp/app.psgi
    + MyApp/MyApp.pm
    + MyApp/MyApp.pl
    + MyApp/public
    + MyApp/public/css
    + MyApp/public/css/style.css
    + MyApp/public/css/error.css
    + MyApp/public/images
    + MyApp/public/404.html
    + MyApp/public/dispatch.fcgi
    + MyApp/public/dispatch.cgi
    + MyApp/public/500.html

The dancer application creates a views folder, which contains layout and templates. It contains sane defaults you can use to start. It also creates a config.yaml file and an environments folder for environment-specific configurations. MyApp.pm and MyApp.pl are the main application files. MyApp.pl includes a built-in webserver for the development (or even deployment!) of your application. The public folder contains default CSS and images.

This directory tree includes a few other interesting files; these are dispatchers for various backends. The PSGI dispatcher is app.psgi. The CGI and FCGI dispatchers are public/dispatch.cgi and public/dispatch.fcgi, respectively.

Look in MyApp/MyApp.pm. Dancing really is this simple!

    package MyApp;
    use Dancer;

    get '/' => sub {
        template 'index';
    };

    true;

What does this all mean?

Routes

Dancer uses the notion of routes to specify the paths your users might take in your website. All you need in order to write a Dancer application is to define routes. Routes are not only simple, but concise and versatile. They support variables (named matching, wildcard matching), regular expressions and even conditional matching.

Here are a few examples:

    get '/' => sub {
        return 'hello world!';
    };

This route defines the root path of the application. If someone reaches http://example.com/, it will match this route.

The word get signifies the HTTP method (GET) for which the path exists. If you use a web form, you need a route for a POST method:

    post '/user/add/' => sub {
        # create a user using the data from the form
    };

There are a few more methods (del for DELETE, put for PUT). You can also use any to provide a single route for all HTTP methods or for several specific methods:

    any ['get', 'post'] => sub {
        # both post and get will reach here!
    };

Variables are clean and simple:

    get '/user/view/:username/' => sub {
        my $username = params->{username};
        template 'users' => { username => $username };
    };

This route matches http://example.com/user/view/variable/, while variable can be of any type.

Of course, you can write a more complex wildcard matching:

    get '/download/*.*' => sub {
        # we extract the wild card matching using splat
        my ( $file, $ext ) = splat;
    };

If you feel rambunctious, you can define a regular expression:

    get r( '/hello/([\w]+)' ) => sub {
        my ($name) = splat;
    };

Note that in these examples, the splat keyword returns the values that the wildcards (the * used in routes) or regular expressions (declared with r()) match. As a convenience, note also that you do not have to escape the forward slash regex delimiters used in r(); Dancer escapes them for you.

Multiple Routes

When writing many routes, you might find it easier to separate them to different files according to their prefixes. Dancer provides prefix and load to help you with that.

    # in main Dancer application:
    load 'UserRoutes.pm';

    # in UserRoutes.pm:
    use Dancer ':syntax'; # importing just the syntax to create routes
    prefix '/user';

    get '/view/'   => sub { ... };
    get '/edit/'   => sub { ... };
    get '/delete/' => sub { ... };

These will match http://example.com/user/view/, http://example.com/user/edit/ and http://example.com/user/delete/, respectively.

Built for scalability

Dancer has a built-in route caching mechanism, making sure that even when you have a lot of routes, it will be able to serve them at almost the same speed as though you had only a few routes. This means that even if you have 600 routes, you do not have to worry about your application being slow!

Variables

Dancer supports internal variables. Declare them with var, and you can later fetch them inside your routes:

    var waiter => 'sawyer';

    get '/welcome/' => sub {
        my $name = vars->{waiter};
        return "Hi, I'm $name and I'll be your waiter this evening.";
    };

Filters

Sometimes you want to be able to specify code to run before any route. KiokuDB, for example, requires you to make a scope whenever you want to work with the database. This is easy to automate with the before filter:

    before sub {
        var scope => $dir->new_scope;
    };

Another common technique is to verify a session:

    before sub {
        if ( !session('user') && request->path_info !~ m{^/login} ) {
            # Pass the original path requested along to the handler:
            var requested_path => request->path_info;
            request->path_info('/login');
        }
    };

Templates

Dancer will return to the user agent whatever you return from a route, just like PSGI does. "Hello, world!" in Dancer is:

    get '/' => sub { 'Hello, world!' };

Plain text isn't always what you want, so Dancer has powerful support for templates. There are various template engines available (Template::Toolkit, Template::Tiny, Tenjin, Text::Haml, and Mason, to name a few). Dancer also provides a default simple template engine called Dancer::Template::Simple. This gives you a simple self-contained template engine at no additional cost!

The template keyword allows you to specify which template to process and which variables to pass to the template:

    get '/user/view/:name' => sub {
        my $name = params->{name};

        # Dancer adds .tt automatically, but this is configurable
        template 'show_user' => {
            name => $name,
            user => get_user($name),
        };
    };

Dancer automatically supplies you an encompassing layout for your templates, much like Template's WRAPPER option. This built-in template means you can use the layout with other template engines, such as Template::Tiny.

Dancer accomplishes this by rendering two templates: the one you provided and a (configurable) layout template. The layout template gets the output of rendering your template as a content variable, then embeds that content in the general page layout.

The default templates that come with Dancer demonstrate this point very well. Here's main.tt, the default layout:

    <html><head><!-- some default css --></head>
    <body>
    <% content %>
    </body>
    </html>

Serializers make RESTing easier

Serializers are a new feature in Dancer (available since version 1.170). They allow automatic serialization for your output in various forms (Data::Dumper, YAML, or JSON) to shorten the amount of code you have to write in your application.

When programming a RESTful service, the JSON serializer cuts down much of your code by automatically serializing your output. This makes your server-side AJAX code much more efficient and less boilerplate code for you to write.

File uploads are fun

File uploads exist since version 1.170. Within a route, write:

    # several files
    my @files = request->upload();

    # single file
    my $file  = request->upload();

    # then you can do several things with that file
    $file->copy_to('/my/upload/folder');
    my $fh       = $file->file_handle;
    my $content  = $file->content;
    my $filename = $file->filename;

Easy configuration

You can configure everything (logging, session handling, template layout, file locations) in Dancer using the main configuration file (appdir/config.yml). There are configuration files for your specific environment (production and development) and you can provide environment-specific configurations in the corresponding file (appdir/environments/development.yml, for example).

Summary

While Dancer is still evolving, it is already a production-ready simple-yet-powerful web framework lets you get from zero to web in record time. Put on your dancing shoes, define your steps, and bust a move!

Dancer is available on the CPAN (Dancer), and Dancer development takes place on Github.

Visit the home of the Perl programming language: Perl.org

Sponsored by

Monthly Archives

Powered by Movable Type 5.13-en