January 2011 Archives

The Method Keyword, take two

| 4 Comments

I've published a second version of a patch to add a method keyword to Perl 5. The main difference in this patch is building up the optree to perform my $self = shift; instead of stuffing that code into the lexer at the appropriate place:

methbody : '{' remember addimplicitshift stmtseq '}'
            {
                if (PL_parser->copline > (line_t)IVAL($1))
                  PL_parser->copline = (line_t)IVAL($1);
              $$ = block_end($3, op_append_list(OP_LINESEQ, $3, $4));
              TOKEN_GETMAD($2,$$,'{');
              TOKEN_GETMAD($4,$$,'}');
            }
    ;

addimplicitshift :
    { OP *selfsv      = newOP(OP_PADSV, 0);
      OP *rv2av       = newUNOP(OP_RV2AV, 0, newGVOP(OP_GV, 0, PL_defgv));
      OP *shift       = newUNOP(OP_SHIFT, 0, rv2av);

      selfsv->op_targ = (I32)Perl_allocmy(aTHX_ STR_WITH_LEN("$self"), 0);
      $$              = newSTATEOP(0, NULL,
                            newASSIGNOP(OPf_STACKED, selfsv, 0, shift));
     }
    ;

The second production is most interesting. It does the work of creating the Perl 5 optree you can see from running:

$ perl -MO=Concise,meth -e 'sub meth { my $self = shift; }'
main::meth:
7  <1> leavesub[1 ref] K/REFC,1 ->(end)
-     <@> lineseq KP ->7
1        <;> nextstate(main 1 -e:1) v ->2
6        <2> sassign sKS/2 ->7
4           <1> shift sK/1 ->5
3              <1> rv2av[t2] sKRM/1 ->4
2                 <$> gv(*_) s ->3
5           <0> padsv[$self:1,2] sRM*/LVINTRO ->6

You don't have to understand all of that, but you can see that this is obviously a tree structure. addimplicitshift creates the branch staring at nextstate (op 1) with a sibling sassign (op 6). Other productions have already set up the body of the sub and its lexical scope, so the call to Perl_allocmy only has to give the name of a new lexical ($self). Its return value is the location of the created variable in the lexical storage pad, so that the opcode to access the value of $self can retrieve it correctly.

With that lexical created before the parser parses the literal body of the method from the source code, any other references to $self refer to the lexical implicitly created thanks to the method keyword such that:

use feature 'method';

method oops
{
    my $self = shift;
}

... produces a warning:

"my" variable $self masks earlier declaration in same scope

I suspect there's a reasonably easy way to make the method keyword work nicely with projects such as MooseX::Declare in code such as:

use 5.014;
use MooseX::Declare;

method register(Str $name, Int $age) { ... }

... but despite the advantages of a method keyword in Perl 5, I've done about as much coding on this as I want to do without more support that it might eventually go into Perl 5.

Update: IBM dW and the author have improved the code; I've followed up at Politely Suggesting Improvements.

IBM's developerWorks published an article yesterday describing a simple Ajax web login service.

The original code was horribly insecure, Bobby Tables-style "Anyone can log in without knowing a password merely by manipulating the query parameters" insecure. Fortunately, IBM fixed the code. Unfortunately, it's still bad Perl 5:

#!/usr/bin/perl
# BAD CODE DO NOT USE use CGI qw(:all);
# BAD CODE DO NOT USE use DBI;
# BAD CODE DO NOT USE use DBD::mysql;
# BAD CODE DO NOT USE
# BAD CODE DO NOT USE # read the CGI params
# BAD CODE DO NOT USE $CGI = new CGI();
# BAD CODE DO NOT USE $username = $CGI->param("username");
# BAD CODE DO NOT USE $password = $CGI->param("password");
# BAD CODE DO NOT USE
# BAD CODE DO NOT USE # connect to the database
# BAD CODE DO NOT USE $DBH = DBI->connect("DBI:mysql:database=mydb;host=localhost;port=2009",
# BAD CODE DO NOT USE                                         "mydbusername", "mydbpassword")
# BAD CODE DO NOT USE   or die($DBI::errstr);
# BAD CODE DO NOT USE
# BAD CODE DO NOT USE # check the username and password in the database
# BAD CODE DO NOT USE $query = qq{SELECT id FROM users WHERE username=? && password=?};
# BAD CODE DO NOT USE $query = $DBH->prepare($query);
# BAD CODE DO NOT USE $query->execute($username,$password);
# BAD CODE DO NOT USE $ref = $query->fetchrow_hashref() || 0;
# BAD CODE DO NOT USE $userID = $ref->{"id"};
# BAD CODE DO NOT USE
# BAD CODE DO NOT USE # create a JSON string according to the database result
# BAD CODE DO NOT USE $JSON = ($userID) ?
# BAD CODE DO NOT USE         qq{{"success" : "login is successful", "userid" : "$userID"}} :
# BAD CODE DO NOT USE         qq{{"error" : "username or password is wrong"}};
# BAD CODE DO NOT USE
# BAD CODE DO NOT USE # return JSON string
# BAD CODE DO NOT USE print qq{Content-type: application/json; charset=utf8\n\n};
# BAD CODE DO NOT USE print $JSON;

Perhaps "bad" is too strong a word. Here's that code cleaned up and written with a better foundation for writing real code. (After all, is this article not intended to give people a starting point for writing real code?)

#!/usr/bin/perl -T

use strict;
use warnings;

use CGI;
use DBI;

my $q        = CGI->new;
my $username = $q->param("username");
my $password = $q->param("password");

my $dbh = DBI->connect(
    'DBI:mysql:database=mydb;host=localhost;port=2009',
    'mydbusername', 'mydbpassword'
) or die $DBI::errstr;

my $sth = $dbh->prepare(
    'SELECT id FROM users WHERE username=? and password=?;'
);
$sth->execute($username, $password);

my $json;

if (my ($id) = $sth->fetchrow_array)
{
    $json = qq|{"success" : "login is successful", "userid" : "$id"}|;
}
else
{
    $json = qq|{"error" : "username or password is wrong"}|;
}

print $q->header(
    -type    => 'application/json',
    -charset =>  'utf-8',
), $json;

The differences are minor, but the corrected version of the code is a little less clunky. It follows the Perl style guide more closely (using the idioms of both the CGI and DBI modules) and avoids unnecessary work.

Is this nitpicky?

Perhaps. Perl is nothing if not pragmatic... but if you're going to publish example code used as the core of a login system, why wouldn't you write the best code you possibly can? It may be acceptable to disclaim responsibility for even explaining the security problems of storing plaintext passwords in the database, but posting code vulnerable to SQL injections in 2011 is irresponsible.

It's okay to write baby Perl, but it's baffingly irresponsible to publish said baby Perl as an example from which you expect other novices to learn.

It's almost like publishing home chemistry experiments for second graders where half of the instructions are "Mix together household cleaning ingredients. Be careful; some of them might be dangerous if you mix them together, but that's not the point of these instructions, so you are on your own."

With that said, some people have criticized the example for the use of the CGI module and the CGI mechanism for dynamic web programs in 2011—but that's a well-intentioned if wrong-headed criticism.

Certainly Plack offers an easier mechanism of experimentation and example deployment (which scales to production-ready deployment easily), once you understand Plack and have it installed and configured for your application...

... but for didactic purposes, as a baseline execution model which is relatively easy to understand due to its maturity and ubiquity, CGI is a decent choice for deployment.

The Perl world does need more articles and posts and examples of how to use Plack to replace the CGI model in all of its forms, but the irresponsibility in publishing this article rests with the editors who allowed the further propagation of bad Perl cobbled together.

Your EDSL is only Pretty in Stockholm

| 3 Comments

Disclaimers:

  • Catalyst chained dispatching is great
  • Dave Rolsky is a fantastic, underpraised hacker, a great guy, and one of the first people to say that an interface or implementation could use improvement
  • Martin Fowler is smart and a deep thinker
  • I like MooseX::Declare and its ilk
  • I don't object to what these systems do; I question how they do it
  • If it makes sense for you—if you've thought about the benefits and drawbacks and the benefits outweigh the drawbacks and costs—use it with no quibbles or qualms on my part. I do sometimes.

Your embedded so-called "domain specific language" is only pretty if your language's liberation army has kidnapped and brainwashed you so long ago that your notion of beauty and concision is horribly warped.

To wit:

  use CatalystX::Routes;

  BEGIN { extends 'Catalyst::Controller'; }

  # /user/:user_id

  chain_point '_set_user'
      => chained '/'
      => path_part 'user'
      => capture_args 1
      => sub {
          my $self = shift;
          my $c    = shift;
          my $user_id = shift;

          $c->stash()->{user} = ...;
      };

... is not particularly pretty. It may make the intent of the declaration of routing clearer than the alternative:

sub _set_user :Chained('/') :PathPart('user') :CaptureArgs(1)
{
    my $self = shift;
    my $c    = shift;
    my $user_id = shift;

    $c->stash()->{user} = ...;
}

... but suggesting that it's pretty goes a bit far. I don't have many better syntaxes in mind, but if I could remove the inline => sub { ... } and the need for fat arrows everywhere, I would. Something like this might be more aesthetically pleasing:

chained:      /
path_part:    user
capture_args: 1
method _set_user($c, $user_id)
{
    ...
}

... although it might be fun to write:

method _set_user($c, $user_id)
as user, chained to /, capturing one arg
{
    ...
}

... if route declarations must be in the same file or attached to the same method as declarations. Then again, the Catalyst debugging syntax is awfully clear:

//*

Perl 5 is hardly the only offender in the syntax department though. Here's a so-called embedded DSL in Python 2:

with create_table("Employee") as t:
    t.first_name = {"type" : "char", "length" : 30 }
    t.last_name  = {"type" : "char", "length" : 30 }
    t.age        = {"type" : "int"}

To whom is this nicer than SQL? (You'd almost think someone had already created a language specific to the domain of describing relational data structures.)

Somehow Ruby fans fail to notice the baffling need to sprinkle syntax all over their tooth-decaying sugar, as in Cucumber, where you get the illusion of writing test specifications in plain English as well as the absolute joy of writing and maintaining regular expressions to extract the necessary data from them.

That's right, the important data structure in your test suite is semi-structured text:

Feature: Addition
  In order to avoid silly mistakes
  As a math idiot
  I want to be told the sum of two numbers

  Scenario Outline: Add two numbers
    Given I have entered <input_1> into the calculator
    And I have entered <input_2> into the calculator
    When I press add
    Then the result should be <output> on the screen

  Examples:
    | input_1 | input_2 | output |
    | 20      | 30      | 50     |
    | 2       | 5       | 7      |
    | 0       | 40      | 40     |

... and you still have to parse it yourself, in an ad hoc fashion:

Given /I have entered (.*) into the calculator/ do |n|
    calculator = Calculator.new
    calculator.push(n.to_i)
end

There's a cleverness there to be sure, but is that really the best the programming world can provide?

Lisps fare little better, where outside of Dylan, every Lisp program ends up looking like every other Lisp program. At least XSLT had the good grace to reveal that homoiconicity means that ugly languages make for programs that are ugly to the bone.

Designing great languages is difficult. That's one reason why there are so many languages. If the best you can do as the writer of a so-called embedded dynamic language is to find some corner cases in the syntax of your host language then sprinkle regular expressions around, you haven't done much at all. (Tell me a non-programmer is always going to follow Cucumber's "But it's only semi-structured plain text, it's so eeeeeeeeeezy to write!" semi-structured format in a way that your ad hoc regular expressions always match perfectly, and I'll show you non-programmers who write their plain-text behaviors in Microsoft Word.)

Again, if these tools make your life easier, great. I use them sometimes myself. I just don't dislocate my shoulder patting myself on the back for my cleverness in doing so. Maybe some of the energy spent trying to twist a host language into not looking like the host language would be better spent writing simpler, more fluent interfaces in the dominant and effective idioms—if not writing actual new domain-specific languages, with parsers and everything.

The Little Conveniences

| 5 Comments

My favorite new feature in Perl 5.10.0 was say. How silly is that? say works like this:

use feature 'say';

# replace this
print "This is some text!\n";

# with this

say 'This is some text';

All it does it add a newline to the end of the printed line. Yes, it's two characters shorter, but it does almost nothing... except that it's two characters shorter, it adds behavior you add most of the time, it lets you avoid unnecessary interpolation, and did I mention that \n is actually a little bit ugly in a string?

I liked it so much from Perl 6, I implemented it in Parrot for the four fundamental datatypes.

I liked it so much, I wrote Modern::Perl to enable it (and everything else I like in Perl 5.10) with a single command.

As silly as that all sounds, I've heard from other people I trust that this single little feature is almost indispensible. It's a tiny convenience. It's a small thing. Yet once you acclimate to its presence, its simplicity, its usability, its utility, you appreciate what it does.

The same goes for Moose, or MooseX::Declare, or other convenience mechanisms that are, on their face, purely syntax. Syntactic sugar gets a bad reputation when it obfuscates the necessary, but it doesn't get enough credit when it illuminates the important by removing the unnecessary.

That's why I so dislike the default argument against adding useful and necessary syntax. It's so very easy to say "A class is just a package and a method is just a function." It's true, and yet it's so trivial, as if the Church-Turing equivalence were solely an argument against any new syntax: a branch is just a goto, a lexical variable is just a store in an offset, and function parameters were merely a list on a stack somewhere you can unpack yourself in any fashion you like.

Yes, that's all true, but how so much does it miss the point.

Sometimes a little bit of syntax can make your program simpler, more beautiful, more elegant, more maintainable, and more enjoyable. After all, shouldn't you seek to enjoy programming?

What Else a Method Keyword Could Do

| 2 Comments

Suppose someone applied a patch to add the method keyword to Perl 5. The benefits could go far beyond the simplicity of intent and implementation you get from writing:

use feature 'method';

method do_awesome_things
{
    $self->do_something;
    $self->do_another_thing;
    $self->do_yet_another_great_thing;
}

Sure, you save one line per method and you've communicated your intent that do_awesome_things() is really a method. (The argument "Can't you just put a comment or POD somewhere saying that do_awesome_things() is a method?" is exceedingly silly. You might as well use goto for all of your control flow. After all, you can always add a comment # this is a while loop.)

With method, you've done more than communicate to programmers that your method is a method. You've told Perl itself that your method is a method, and Perl can do many, many new things with that information. If Perl somehow marked the internal data structure it creates to represent methods (whether setting a flag or extending its CV structure with a MV structure), it could distinguish between functions and methods. This would allow several useful new features, not limited to:

  • Perl could detect the invocation of a method as a function and give a warning (which you could promote to an exception with use warnings)
  • Perl could fix the SUPER problem
  • Perl could add an API to namespaces to retrieve the names of only the methods in a namespace
  • If Perl 5 had a class keyword, it could compile the class, resolve all of the uses of functions within the class, then remove functions from the class's namespace to leave only methods, so as to avoid inadvertent namespace pollution with non-methods. See also namespace::autoclean.

You get these benefits by adding this feature to the Perl 5 core. You can sort of emulate some of them with CPAN distributions—but in the core, you can make the need for some distributions and big chunks of features of some distributions disappear. Some flaws you can only truly fix within the language itself, and not in its ecosystem.

Adding a Method Keyword to Perl 5

| 19 Comments

On p5p, David Golden suggested adding use feature 'method'; as a simple extension to Perl 5 which adds a method keyword to declare a method, then shift off the invocant and make it available within the body of the method.

I wrote a patch to enable method in feature.pm. The patch looks longer than it is. The important user-side example is in the simple test suite I added:

package SomeClass;

use strict;
use warnings;

use feature 'method';

sub new {
    my ($class, $value) = @_;
    bless \$value, $class;
}

method get_value {
    return $$self;
}

method dup_value
{
    return    $$self
    . reverse $$self;
}

method set_value :lvalue
{
    $$self;
}

method ctor
{
    my $value = shift;
    bless \$value, $self;
}

package main;

my $sc = SomeClass->new( 'instance variable' );

can_ok($sc, 'get_value');
can_ok('SomeClass', 'set_value');
is($sc->get_value, 'instance variable', 'simple method should work');
is($sc->dup_value, 'instance variableelbairav ecnatsni',
    'method using additional $self should work');
$sc->set_value = 'foo';
is($sc->get_value, 'foo', ':lvalue attribute should work');

$sc = SomeClass->ctor( 'method constructor' );
is($sc->get_value, 'method constructor',
    'method should work for constructor too');

done_testing();

As you can see, with use feature 'method'; in scope, the method keyword is a synonym for sub which implicitly adds a single line at the start of the body of the method: my $self = shift;.

Making this work meant adding method to the tokenizer as a keyword recognized only in the scope with use feature 'method'; enabled. That explains the patches to lib/feature.pm, keywords.h, perl_keyword.pl, and regen/keywords.pl, as well as the the second half of the changes to toke.c.

The first half of the changes to toke.c are a copy and paste and specialization of the special handling of the sub keyword. I had to do this for two reasons. First, the sub handling always returns a token representing SUB to the parser, and I needed to return something special. I chose the token METH instead. Second, it makes little sense to support prototypes on methods, as Perl 5 cannot resolve prototypes across method dispatch. I removed the portion of the sub tokenizing related to that. (This batch of code isn't an example of screechingly obviousness; it could become cleaner as I see more unnecessary code to remove.)

With all of that in place, the tokenizer provides a stream of tokens to the acutal parser in perly.y. The patch adds an alternation to one production and two supplementary productions.

The alternation to statement processing starts when the parser encounters the METH token. A method starts with meth, runs the special startsubparse production to set up the new subroutine scope, has a name, has an optional attribute list, and then has a method body. The latter is a new production.

A method body has curly braces delimiting it. It then runs a special new production called addimplicitshift (did I mention the phrase "screechingly obvious"?), runs an existing production called remember to start a new lexical scope, then gathers a list of statements, and finally encounters the ending curly brace.

The addimplicitshift production is the most interesting part of this whole process. It uses the core lex_stuff_pvs() function to add a single line of Perl 5 code: my $self = shift;. Perl will parse that line as if it had always been the first line of the body of the method, even though the parser added it itself.

This means that if you wrote:

use feature 'method';

method some_method
{
    my $self = shift;
    ...
}

... you'll get the warning you expect about a redeclaration of a lexical, with the correct the line number.

Does this work well with CPAN modules which declare their own method keywords? It's not incompatible with them, in the sense that the only code in the world which gets any use out of use feature 'method'; right now is the test in my patch. Yet something like MooseX::Declare may (I haven't tested it) be incompatible if and only if you use MooseX::Declare and use feature 'method' in the same scope.

A larger question is whether this is a valuable feature. Certainly it offers two modest advantages, by marking the intent of the developer to distinguish between a method and a function and by removing a line of boilerplate from every method. (Given that most of my methods are between three and ten lines long, saving double-digit percentages of their length is a tremendous savings of code.)

Will this feature get in Perl 5.14? I don't know. I have my doubts—the implementation could be cleaner, the ultimate syntax could change to use something other than my $self = shift;, and there's undoubtedly a long line of people who believe that the only way to prototype a proposed change to the Perl 5 core is to write a CPAN module (at which point a long line of people is happy to say "Why would you want that in core? There's already a CPAN module for it!").

Regardless of all of that, I can think of a fair few advantages to doing something like this in the core. I'll explain those tomorrow.

The article Why You Can't Hire Great Perl Programmers addressed the core Perl community. We need to encourage Perl dabblers to improve their skills and to join the community.

Several commenters noted that the article did not address the employer side of hiring. Certainly an employer offering $15 an hour for Perl programmers in Silicon Valley or New York City or Chicago or Seattle will have to work much harder to entice great programmers than someone paying competitive wages.

Editor's Note: The whitepaper Where to find a programmer who knows modern Perl now addresses this question. If you're hiring, the guidelines there may help you.

There's another point to which some people alluded but no one, to my knowledge, addressed directly. It's not easy to identify good programmers in any language unless you're a good programmer yourself. For all of the flaws in the infamous interviewing systems of Microsoft or Google (and there are many flaws in those interviewing processes), they have the advantage that people who clearly don't know what they're doing tend to expose their ignorance.

You probably don't want to go through the time, expense, and nonsense of those hiring practices (as if you could afford them), and, for various reasons, there will never be a Perl certification test widely accepted as useful and informative. Even still, there are ways to identify good Perl 5 programmers. Here's a list of questions every good Perl programmer should be able to answer effectively:

  • What do variable sigils indicate in Perl 5?
  • What's the difference between accessing an array element with $items[$index] and @items[$index]?
  • What's the difference between == and eq?
  • What do you get if you evaluate a hash in list context?
  • How do you look up keywords in the Perl documentation?
  • What is the difference between a function and a method in Perl 5?
  • When does Perl 5 reclaim the memory used by a variable?
  • How do you ensure that the default scope of a variable is lexical?
  • How do you load and import symbols from a Perl 5 module?
  • What governs how Perl 5 loads modules How can you influence the list of directories from which perl attempts to load modules?
  • How do you look up error messages in the Perl 5 documentation? (Award bonus points for knowing how to enable explanations of all error messages encountered.)
  • What happens when you pass an array into a function?
  • How do you pass one or more distinct arrays into a function?
  • What is the difference, on the caller side, between return; and return undef;?
  • Where do tests go in a standard CPAN distribution?
  • How do you run tests in a standard CPAN distribution?
  • What command do you use to install new distributions from the CPAN?
  • Why would you use the three-argument form of the open builtin?
  • How do you detect (and report) errors from system calls such as open? (Award bonus points for knowing how to enable automatic detection and reporting of errors.)
  • How do you throw an exception in Perl 5?
  • How do you catch an exception in Perl 5?
  • What is the difference between reading a file with for and with while?
  • How do you handle parameters within a method or function in Perl 5?
  • What do parentheses around the variable name in my ($value) = @_; mean, and what would happen if you removed them?
  • Is new a builtin function/keyword?
  • How do you read the documentation of a core library? A CPAN module?
  • How do you access only the values of a Perl 5 hash?

None of these are trick questions. All of them have simple, unambiguous answers that demonstrate a solid understanding of Perl 5, its philosophy, and its practical use. A good Perl 5 programmer should be able to answer at least 80% of these questions with no trouble. These are not the only questions a good Perl programmer should be able to answer, but anyone who can't answer these questions with ease needs to study more Perl.

The specific needs of your business may dictate further considerations, such as experience with well-understood Perl 5 technologies, but you can begin the technical evaluation of a candidate this way.

If you're starting to learn Perl 5, this list is also a good way to measure your skills. You should be able to answer all of these questions with a little bit of study and practice. All of the answers are available in any good Perl 5 text, including my own Modern Perl.

(You can buy Modern Perl at Powell's, buy Modern Perl at Barnes and Noble, buy Modern Perl at Amazon.com, or download Modern Perl for free and then recommend it to your friends, write a great review, or otherwise spread the word.)

On a recent client project, I added a plugin system to the business logic. Whenever certain operations occur (a new user creates an account, a password changes, et cetera), the system needs to be able to perform arbitrary external operations. I know what some of these operations are (logging, updating external authentication systems), but the client will add more to the system in the future.

After some design work, I settled on a role, here called MyApp::Role::Activates. It applies to a model class with the code:

package MyApp::Schema::ResultSet::User;

use Moose;
use Modern::Perl;
use namespace::autoclean;

extends 'DBIx::Class::ResultSet';
with 'MyApp::Role::Activates', { namespaces => [ 'MyApp::Plugin' ] };

...

This parametric role allows the use of specific namespaces in which to find its plugins. That customization gives a genericity which I can reuse and exploit in the future, if not in this project. The role provides a single method. For example, when validating the parameters of a new user and creating that new user:

sub validate_and_create
{
    my ($class, $args) = @_;
    my $params         = $class->validate_params( $args );
    my $user           = $class->create( $params );

    $class->activate_plugins( user_created => $user );
    return $user;
}

All I had to do to add this event system to my model was to add this role to each model class and figure out the name of the event and the right arguments to that event. The role itself is very simple:

package MyApp::Role::Activate;

use strict;
use warnings;

use Try::Tiny;
use namespace::autoclean;
use Module::Pluggable::Object;
use MooseX::Role::Parameterized;

parameter 'namespaces', isa => 'ArrayRef', required => 1;

role
{
    my $p          = shift;
    my $namespaces = $p->namespaces;

    has 'plugins', is => 'ro', isa => 'ArrayRef', lazy_build => 1;

    method _build_plugins => sub
    {
        return
        [
            Module::Pluggable::Object->new(
                instantiate => 'new',
                search_path => $namespaces,
            )->plugins
        ];
    };

    method activate_plugins => sub
    {
        my ($self, $method, @args) = @_;

        for my $plugin (@{ $self->plugins })
        {
            try { $plugin->$method( @args ) };
        }
    };
};

This code is immensely simpler thanks to Module::Pluggable. The laziness of the plugins attribute means that it's cheap to apply this role to classes without having to scour the filesystem for plugins until they're necessary.

The abstraction of this role also allows me to produce an asynchronous plugin system if necessary. Right now, plugin activation always takes place synchronously. Only this code needs to change to change that.

The final part of the system is a role which represents a plugin:

package MyApp::Role::Plugin;

use Moose::Role;

sub user_created          {}
sub user_password_changed {}
...

1;

All valid plugins should perform this role. They can choose not to implement some or all of the methods of this role, in which case they will do nothing (not even crash) for a given action. Documenting how to write a plugin is a case of explaining a bit of boilerplate ("Here's how to write a Moose class which consumes this role") and listing the appropriate plugin methods and their arguments.

The result is a system where my client can add arbitrary features without my help. There are ways in which to make the system more robust if necessary, but for now it's a fine and simple and—in some ways—elegant system.

(I could have gone further in the design by adding annotations to methods in the model which should throw events, but I appreciate the simplicity of "A plugin activation is just a method call". Sometimes it's better not to introduce syntax, as tempting as creating declarative decorations may be, for the sake of not introducing extra work.)

If this is your first visit to my site, welcome. I've written a book called Modern Perl which explains how Perl 5 works and how to program Perl effectively. Electronic versions are free to download and redistribute, and print versions are for sale. I hope the book is useful to you; please tell other people about it.

If you're an employer or recruiter looking for good Perl developers, the whitepaper Where to find a programmer who knows modern Perl may help you. See also How to Identify a Good Perl Programmer.

If you're a programmer yourself, I recommend The Lemon Market of Programming Language Adoption, which explores the economics of why programmer salaries get pushed down in popular fields.

Hiring Great Programmers is Difficult

One of the persistent rationalizations for not creating new software in Perl is that it's difficult to find great Perl developers.

That's half true.

It's difficult to find great developers in almost any language, unless your language community is so small that it's self-selecting against people just in it for a paycheck. (Even in that case, the truly great developers who know Haskell or Smalltalk or Common Lisp tend not to be in want of work for long.)

In another sense, it's difficult to hire great Perl developers because it's so very easy to become a mediocre Perl developer. Despite the repeated myth that Perl is difficult to learn, it's not. It's shockingly easy to learn just enough Perl to build a working system. If you remember the mid to late '90s at all, think back to all of the tiny little form scripts that you could FTP into a cgi-bin directory. Most weren't worth using, due to various limitations, but real people learned just enough Perl to write them.

It's more true to say that Perl programming is easy to learn but not simple to learn well. (This is not unique to Perl; you can explain Smalltalk's syntax to a class of rapt sixth graders armed with only a 3x5 notecard, but said students won't approach Ward Cunningham in ability any time soon.) Perl, like PHP, suffers somewhat from the ease at which you can learn just enough to be productive. In terms of language design, there's no initial turnstile which keeps people out who aren't yet smart or experienced or stubborn enough to figure out how to wrestle with a compiler, or type errors, or the precise alignment of invisible characters, or configuring a web server, or setting up authentication with a database.

There's also nothing in the language which forces people to stop every hundred lines or ten programs or two weeks to push them up the learning curve a little bit more.

The result is a language that lots of people know a little bit. Many people know it well, but the group of people with a little bit of knowledge (likely due to ad hoc experimentation and intuition based on previous familiarity with another programming language or Unix culture or just copy and paste osmosis from a barely-working heap of sticks left by the previous maintainer) dwarfs that smaller group of experienced programmers.

Hiring from this pool of experienced programmers would be easier if the people hiring Perl programmers knew to hire from this pool of experienced programmers—but this problem exacerbates itself. Without a cultural or financial incentive to encourage novices to become adepts, only the most stubborn, the most motivated, the most curious, and the most fortunate realize that tools such as Perl::Critic and Test::More and Moose exist. It's one thing to know about the CPAN and use it when it helps you—that's what a mature programmer will do—but it's far too easy to get by without realizing how many great tools are available. This is a failure of Perl culture and documentation, that the CPAN isn't better publicized.

Then again, too few novices even know how to take advantage of all of the Perl documentation that comes with every complete Perl installation.

One solution, as I see it, has two parts.

Perl Programming Skills

First, if you want to hire great Perl developers, look for people who:

  • Know how to use modern Perl tools
  • Have used CPAN modules
  • Participate in groups such as Perl Mongers, PerlMonks, and YAPCs
  • Subscribe to mailing lists for projects of interest
  • Own, or have read, great books like Perl Best Practices, Effective Perl Programming, or my own Modern Perl

Perl Programming Promotion

Second, the existing community of Perl developers can expand itself by finding novices and dabblers and encouraging them to continue their education in the ways of Perl. Part of that is evangelism, such as How to turn mediocre Perl code into elegant Perl code or How to take advantage of improvements in Perl. Part of that is spreading the message that discipline and education are the solutions to unmaintainable code. Part of that is expanding the boundaries of the existing Perl community to include the silent majority of people who've programmed Perl to demonstrate how their lives can be easier when their code is shorter, simpler, more robust, safer, more secure, more powerful, and easier to understand and to maintain.

One important step is to promote all of the wonderful language extensions available on the CPAN—not that you must use Moose or Moo or whatever to be a good Perl programmer, but that the tools are available for you to use when they help you.

As with almost every other programming language, Perl is only as difficult as we allow ourselves to make it. I believe the Perl community has done a great job in the past few years helping the world's best Perl programmers become more productive. Now we have the opportunity to spread that outside of that community.

A Word about Programmer Salaries

Of course, if you are trying to hire someone to write software that's essential to your business and you're not willing to compensate developers effectively, you're going to have trouble attracting good developers. You don't necessarily have to break the bank on salary; benefits such as working remotely, profit sharing, contributing to free software, allowing time for refactoring, et cetera may all make your business more attractive to good programmers.

If, on the other hand, you treat programming as if it were assembly line work (as if programming were merely the act of transcribing business requirements into code by rote), you're going to get what you deserve: mediocre software written by low bidders.

Hip vs. Useful

| 1 Comment

While agreeing with everything Su-Shee wrote about talking about all of the great things we do in and with and around Perl, it's important to keep one thing in mind: hip isn't always the same thing as useful.

I used to work for a company which used to be great but has now staggered along half-dead for several years now because of mistaking hip for useful.

Every six to twelve weeks a new shiny thing would come along to create a lot of noise among a few dozen early adopters. This frequent fashion show would produce a lot of grand plans about the founder demonstrating his prowess as a kingmaker, of flexing his muscle as eminence gris of the relevant community. Meanwhile the bread and butter projects, the work which had built the company and made it great, were old and dingy because they had the patina of proven use and not the electroplating of "No one's ever heard of this before!"

By all means, some new inventions are novel and some new developments are useful and any serious professional should pay attention to the state of the art (or at least the state of the craft). Yet the relentless assumption that the only way to succeed in our business was to jump out in front of an oncoming train and hope it was a high-speed maglev instead of a wind-up HO scale kid's meal giveaway has gutted a once-promising business.

By all means, do show off the amazing things you create. Show the world that Perl programming is a joyful, creative expression. Yet also remember pragmatism. People use things because they are also useful. There is no shame in failing to convince a sizable herd of the twitterati to recover from its regularly scheduled six-month swoon of the language du jour or to consider that the hundred line lump of spaghetti Perl 4 they wrote back in 1999 has little to do with good Perl as written then, let alone today.

Remember that the bizarro bubble of the Silicon Valley is not the sole determinant of what's worth using, and that half of those companies won't exist next year for reasons completely unrelated to their choice of technology.

By all means, brag for the right reasons. Yet remember always that there is craft in our craft, that for all of the beauty and joy in our creations, we build useful things.

(For example, CPAN has value not solely because it's the largest language repository of free software libraries but also because of its testing, bug reporting, dependency tracking, documenting, reviewing, mirroring, DarkPANning, and archiving ecosystem.)

The moral of this story comes first: Parsimony of axioms is not the sole virtue of language design.

Imagine you're designing PythonPerl 5. What's the minimum feature set you need to implement to provide an object system?

Objects have methods. Objects have attributes. Objects can have classes. (You can write a very workable object system where objects lack classes and only have methods, or messages, and no attributes, but humor me.) Thus you need a mechanism of attribute access, a mechanism of object creation, and a mechanism of method dispatch.

If you already have core language support for an abitrary data structure which associates names with values (a hash, a hashmap, a dict, a table, or whatever you call it), you can steal it to support attributes. It's very easy and tempting; after all, what is an attribute other than a named slot containing a value? (If it's good enough for C programmers, it's good enough for the rest of us.)

If you already have some mechanism for partitioning the world into separate namespaces, methods are almost as easy. You very likely also have functions, so a method can be a function in the appropriate namespace. That's also very easy.(This is better than what C programmers get, as they need a struct full of function pointers as well as the ability to hide that struct from people who shouldn't poke into it. Then again, C programmers are either unconcerned about encapsulation or very used to faking namespaces with prefixes and macros and the use of the static keyword (and, yes, I've written more than my share of pseudo-OO C)).

With those two pieces in place, the obvious question of instance creation and method dispatch almost resolves itself. Object creation means allocating the appropriate hash/map/dict/table and somehow associating it with the appropriate namespace. You can do this by blessing a particular syntactic construct as always obviously creating and associating:

someObj = SomeObj();

... and hiding the details of the hash/map/dict/table behind additional syntax, or you can embrace the minimalism of the need to add only two additional primitives and allow users to perform that association a bit more directly:

bless $hash_ref, 'Some::Class';

Your preference for or against syntax probably guides that decision.

There are other concerns, such as whether you allow inheritance. (You probably do, for two reasons. First, you're not writing a good object system anyway. Second, you know that many people like writing OO code because they believe it's primarily a design strategy to reuse code.) You also have to figure out a method dispatch strategy and how to represent parent and child relationships between classes.

If a class is just a namespace, why add syntax? You could use a variable or some other type of attribute of the namespace to identify a subclassing relationship.

Now go write some code (and not much), and you have a working object system built from a small set of core axioms that your language probably also has.

Isn't minimalism in language design great? (If you still believe you can answer "yes" to that question, see distributions containing "class" on the CPAN.

Minimalism

| 1 Comment

What do Scheme, Bash, and elisp have in common?

They're infinitely flexible and infinitely customizable and, if you force two users with great libraries of customizations to swap profiles, you are a cruel, cruel person.

Programming language design has a strange dogma that minimalism of features is a greater good, that distilling the smallest possible set of elegant core axioms is both possible and profitable. From there, offering this set of axioms leaves the dirty business of making workable software to blue-collar workaday programmers.

(I helped the authors of a book of interviews with programming language designers craft interview questions. Few designers of popular languages believe this fallacy. There may be a connection.)

Minimalism by itself is no vice. The minimalism which leads to insufficiency and fragmentation becomes a vice.

For example, consider perhaps the ultimate counter example of minimalism in programming language design. PHP's multiple searching functions differ in searchtype( $needle, $haystack ) and search_type( $haystack, $needle ) and searchType( $neestack, $haydle ) and other permutations—and these are core language features.Similarly, the Java language's insistence that named classes are the only sufficient mechanism of abstraction leads to the use of XML data structures interpreted to generate code during startup time (as if XML were a sufficient programming language, much less a reasonable syntax for the bytecode generations and modifications necessary to emulate a sort of dynamic language) as well as the use of large IDEs to hide the generation of this XML from hapless workaday programmers.

Similarly, I have a wonderful ~/.aliases file sourced from my ~/.bashrc which contains aliases, aliases which use aliases, functions, functions which use functions and aliases, and other shortcuts I've distilled from repeated tasks. Someone can ask me "Hey, how do you perform memory leak analysis on that specific shared library?" and I can type a short command and confuse everyone because no one else understands my specific aliases.

(Alternately, I can do what a coworker does by refusing to customize my bash environment or my ~/.vimrc or ~/.screenrc and learning to get by with the default configuration on any decent free Unix-like box... but I'm far too impatient for that.)

If programming a large system is, at its heart, the distilling of the problem space to discover the proper terms to describe the business roles of the solution (and I believe that the Forth, Lisp, and Smalltalk people are right to describe it as such), then modern languages must provide appropriate mechanisms to devise, manage, and exploit vocabularies sufficient to solve business problems effectively.

Yet there's also a level beneath which the language of the solution is irrelevant, and that level is almost always "You can roll your own object system!" or "Exception handling is what you make it!" or "Iteration/recursion/goto/call-with-current-continuation is the only true flow control mechanism" or "The hash/cons/char * is the only true data structure!".

In other words, minimalism only works in practice when that minimum overlaps sufficiently with the necessary. Fail to provide the necessary for certain problems and you risk use-but-fragmentation or, perhaps worse, irrelevance in that problem domain.

Next time: minimalism in Perl (believe it).

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

affiliated with ModernPerl.net

Categories

Pages

About this Archive

This page is an archive of entries from January 2011 listed from newest to oldest.

December 2010 is the previous archive.

February 2011 is the next archive.

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


Sponsored by Blender Recipe Reviews and the Trendshare how to invest guide

Powered by the Perl programming language

what is programming?