I've had a few discussions with people about why I wrote Keyword::DEVELOPMENT, a useful, but simple module. In short, it lets you do this:

use Keyword::DEVELOPMENT; # later ... sub consume_item ( $self, $item_slug ) { DEVELOPMENT { # expensive and time-consuming debugging code here } my $inventory = $self->inventory; return $self->new_exchange( slug => 'consume', Steps( Inventory( $inventory => contains => $item ), Consumable( $self => consume => 'item_instance' ), Inventory( $inventory => remove => 'item_instance' ), ), )->attempt; }

The expensive debug block? With Keyword::DEVELOPMENT , is simply fails to exist in production unless the PERL_KEYWORD_DEVELOPMENT environment variable has a true value. Thus, there is no performance overhead to instrumenting your code with complicated debugging logic (as I'm currently doing with Tau Station).

It's been pointed out to me by several people that I can accomplish the above in regular Perl with constant folding. I'll explain what that means and why I prefer the keyword route.

I prefer this module to constant folding because Keyword::DEVELOPMENT is less fragile (assuming you're comfortable with pluggable keywords: they have been available for about 7 years now) and it creates a standard in our codebase.

With constant folding, you can do the following:

#!/usr/bin/env perl use 5.024; use constant DEBUG => $ENV{DEBUG_MY_LOUSY_CODE}; # in exchange... if (DEBUG) { say "Yes, debug!"; } else { say "No, debug!"; }

In the above, if the DEBUG_MY_LOUSY_CODE environment variable doesn't exist, or has a false value, the Perl compiler will see that DEBUG is false, at compile time, and the if block will simply be removed. There won't even be a check for it. It's a powerful tool. Here's the output from perl -MO=Deparse const.pl :

sub BEGIN { require 5.024; } use constant ('DEBUG', 0); use strict; no feature ':all'; use feature ':5.24'; do { say 'No, debug!' }; const.pl syntax OK

Note that the "Yes, debug!" code is not there. That's also what Keyword::DEVELOPMENT does. Except ...

Some dev comes along as says "why are we using the old constant pragma?" So they "fix" the code:

#!/usr/bin/env perl use 5.024; use Const::Fast; const my $DEBUG => $ENV{DEBUG_MY_LOUSY_CODE}; # in exchange... if ($DEBUG) { say "Yes, debug!"; } else { say "No, debug!"; }

And in the deparse:

sub BEGIN { require 5.024; } use Const::Fast; use strict; no feature ':all'; use feature ':5.24'; &const(\my $DEBUG, 0); if ($DEBUG) { say 'Yes, debug!'; } else { say 'No, debug!'; } const.pl syntax OK

So now we still have our if block there, causing a couple of extra ops which may be problematic in hot code.

And then there's this bit I don't understand at all. In the use constant code, if DEBUG is false, we get a do block instead of the if/else checks. Running perl -MO=Concise,-exec const.pl reveals this:

1 <0> enter 2 <;> nextstate(main 188 const.pl:7) v:*,&,{,$,268437504 3 <0> enter v 4 <;> nextstate(main 192 const.pl:11) v:*,&,$,268437504 5 <0> pushmark s 6 <$> const(PV "No, debug!") s 7 <@> say vK 8 <@> leave vKP 9 <@> leave[1 ref] vKP/REFC

Those are the ops we have with this code and represents what Perl sees internally. Note that this optimized code does not have the "Yes, debug!" code.

Here's the same code, but with DEBUG set to true, thus causing the "Yes, debug!" expression to be printed:

1 <0> enter 2 <;> nextstate(main 188 const.pl:7) v:*,&,{,$,268437504 3 <0> pushmark s 4 <$> const(PV "Yes, debug!") s 5 <@> say vK 6 <@> leave[1 ref] vKP/REFC

We don't get to leverage constant folding, but we actually have fewer ops! If you are running very hot code, shaving ops is important. If you take the else block off, you will get fewer opcodes with the constant folding. I don't actually know why this is, but there you go. I hope some internals guru will come along and tell me what I'm missing here :)

I see constant folding being used all the time for these types of optimizations, with constant names like DEBUG , TESTING , DEBUGGING , and so on. With Keyword::DEVELOPMENT :

You get a standard way of handing this

Developers thus learn to understand what is happening

You have less fragility due to not worrying about how constants are handled

It does require Perl 5 version 12 or above because it uses the pluggable keyword syntax, but it's dead simple:

package Keyword::Development; use 5.012; # pluggable keywords use warnings; use Keyword::Simple; sub import { Keyword::Simple::define 'DEVELOPMENT', sub { my ($ref) = @_; if ( $ENV{PERL_KEYWORD_DEVELOPMENT} ) { substr( $$ref, 0, 0 ) = 'if (1)'; } else { substr( $$ref, 0, 0 ) = 'if (0)'; } }; } sub unimport { Keyword::Simple::undefine 'DEVELOPMENT'; }

Having sane standards in your development shop makes everyone's life easier. Every time you can introduce a single way of accomplishing a task, it's less cognitive overhead for developers and means they spend less time wondering "what does that weird bit do?"

Naturally, you can fork the code from github, download it from the CPAN, or contact our company for training or building awesome software for you. Or just contact me at ovid at allaroundtheworld dot fr.

Note: we write awesome software in a variety of languages, not just Perl.