DEV Community

John Napiorkowski
John Napiorkowski

Posted on

Using Modern Perl Features in your Projects

Perl has changed a lot over the years and it can be hard to keep track of what was introduced when and how to enable it in your project. Additionally some new features get back ported via external modules. Usually in a project you want a consistent feature setup across all the modules comprising it. Also you want an easy way to enable new stuff when it comes out and you are able to upgrade.

There's probably several ways to do this but here's the approach I take. I create a '::Syntax' module in the root of my project namespace and use that to setup all the features I want. For example, let's say I have a project "Example". I create a module like so:

package Example::Syntax;

use strict;
use warnings;

use Import::Into;
use Module::Runtime;

sub importables {
  my ($class) = @_;
  return (
    'utf8',
    'strict',
    'warnings',
    ['feature', ':5.16'],
    ['experimental', 'signatures', 'postderef'],
  );
}

sub import {
  my ($class, @args) = @_;
  my $caller = caller;

  foreach my $import_proto($class->importables) {
    my ($module, @args) = (ref($import_proto)||'') eq 'ARRAY' ? 
      @$import_proto : ($import_proto, ());
    Module::Runtime::use_module($module)
      ->import::into($caller, @args)
  }
}

1;
Enter fullscreen mode Exit fullscreen mode

I can then use this in all my projects modules:

package Example::User;

use Example::Syntax;

# Rest of code.
Enter fullscreen mode Exit fullscreen mode

Using 'Example::Syntax' this way is the same as:

package Example::User;

use utf8;
use strict;
use warnings;
use feature ':5.16';
use experimental 'signatures', 'postderef';

# Rest of code.
Enter fullscreen mode Exit fullscreen mode

Later on if you upgrade to a new version of Perl you can just tweak syntax file. For example if you move to Perl 5.38 then signatures are no longer loaded via the experimental pragma. All your projects code will just continue to work correctly.

Although the Perl team goes to a lot of trouble to try and make sure stuff doesn't break across versions there's no reason to not add a bit of extra safety by centralizing your feature setup. Otherwise you might find yourself with a tedious job of having to tweak boilerplate across your projects. Personally I think this approach makes things a bit neater as well, or fewer lines at least.

A quick last note...

It might come to some that you could use this approach to preload some handy modules, like things out of Scalar::Utils for example. I recommend not going crazy here and creating a default setup that might be surprising to newcomers to your project. A light touch is probably best.

Top comments (6)

Collapse
 
peterdragon profile image
Peter Edwards

Thanks both, yes I meant perl-5.10.1 as we have some legacy code running with mod_perl 1 and 5.10.1 was the latest perl I could get to compile with it.
We nearly have it replaced with PSGI and then we can move to latest perl.

In the meantime, I am interested in ways we can simplify common headers and make code work across perl 5.10.1 (legacy mod_perl), 5.16.3 (ships with RedHat 7) and perl-5.38.0 (latest).

I did some testing @jjn1056 and found your approach works fine with perl 5.10.1, 5.16.3 and perl 5.34.0. I trimmed down the feature imports to what would work on 5.10.

# t2.pl
use lib ".";

use Example::Syntax2;
use Example::Foo2;

{
  my $sum = Example::Foo2::foo(1, 3);
  say $sum;
}
Enter fullscreen mode Exit fullscreen mode
# Example/Syntax2.pm 
package Example::Syntax2;

use strict;
use warnings;

use Import::Into;
use Module::Runtime;

sub importables {
  my ($class) = @_;
  return (
    'strict',
    'warnings',
    ['feature', 'say'],
  );
}

sub import {
  my ($class, @args) = @_;
  my $caller = caller;

  foreach my $import_proto($class->importables) {
    my ($module, @args) = (ref($import_proto)||'') eq 'ARRAY' ? 
      @$import_proto : ($import_proto, ());
    Module::Runtime::use_module($module)
      ->import::into($caller, @args)
  }
}

1;
Enter fullscreen mode Exit fullscreen mode
# Example/Foo2.pm 
package Example::Foo2;

use Example::Syntax2;

sub foo {
  return $_[0] + $_[1];
}

1;
Enter fullscreen mode Exit fullscreen mode

testing on RHEL 7

$ /opt/perl-5.10.1/bin/perl t2.pl
4
$ /opt/perl-5.34.0/bin/perl t2.pl
4
$ /usr/bin/perl t2.pl
4
$ perl -v

This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jjn1056 profile image
John Napiorkowski

Looks great, let me know if you need a consultant to help on the PSGI migration, I've done modPerl 1 to PSGI before :). Sounds like you're well on the way but if you get stuck you know where to find me

Collapse
 
peterdragon profile image
Peter Edwards

Nice one. Is there a minimum perl version needed for this, e.g. 10.1?

Collapse
 
jjn1056 profile image
John Napiorkowski

Import::Into and Module::Runtime seems to run on v5.6.0 (!!!) without trouble (you can check CPAN testers if you don't believe me) so you should be able to use my Syntax pragma as a template, however if you are on that old a Perl you won't have too many modern features to enable. That said there's modules on CPAN that try to shoehorn in more modern features that could be enabled using a pragma like this one.

Collapse
 
davehodg profile image
Dave Hodgkinson

5.something surely? Or 5.10.1? The article is about modern Perl so I'd say 5.34 onwards.

Collapse
 
peterdragon profile image
Peter Edwards

perl 5.10 is fairly puny when it comes to features :-)

From perldoc.perl.org/feature#FEATURE-B...

:5.10 bareword_filehandles indirect
multidimensional say state switch