Tom Christiansen

NAME

pluskeys - pragma to declare class- and typo-safe keys to use in objects

SYNOPSIS

    package Some::Package;

    use strict;
    use warnings;

    use pluskeys qw(
        NAME
        RANK
        SERIAL_NUMBER
    );

    ....

    if ($self->{ +RANK } =~ /General/) { .... }

DESCRIPTION

The use pluskeys pragma takes a list of identifiers and creates constants (zero-argument functions) in the caller's package that return their own name prefixed with that package. It is most commonly used from within a class definition to declare the object attributes (that is, its data members) in a way that can be checked at compile time.

The convention is to use a leading + as a "member key" pseudo-prefix when subscripting the hash. This really makes something like +NAME get parsed as NAME() instead.

That way you can use it as the subscript into a hash and have it be "typo-checked" under use strict, because if you try to use one of these that you didn't declare, it will look like an illegal bareword string and make use strict blow up at compile time.

For example, given the example in the SYNOPSIS above, this would be a syntax error:

    if ($self->{ +SERIAL_NUBMER } =~ /999/) { .... }

Because it would produce an error along these lines (adjusting for filename and line number):

 Bareword "SERIAL_NUBMER" not allowed while "strict subs" in use at test-pluskeys line 13.

But this would be ok:

    if ($self->{ +SERIAL_NUMBER } =~ /999/) { .... }

Because that would be interpreted as:

    if ($self->{ SERIAL_NUMBER() } =~ /999/) { .... }

And thus (resolving at compile time into):

    if ($self->{ "Some::Package::SERIAL_NUMBER" } =~ /999/) { .... }

The other thing this does is prefix each key with the current package name, so that +NAME is really Some::Package::NAME. That way each class in an inheritance hierarchy can have its own member data without risk of trampling on some other class using that same key. It's the only safe way to do things when you cannot know what classes will be using what.

The only drawback is that the same notation cannot be used as the left operand to the => operator. This doesn't work:

    %hash = (
        +NAME => "Joe Blow",    # DOESN'T WORK
        +RANK => "peon",        # DOESN'T WORK
    );

Because unlike it use as a braced hash subscript, there it will be interpreted as a bareword string and not complained about. This is due to the auto-quoting behavior of the => operator.

Instead you would have to write that one this way:

    %hash = (
        NAME() => "Joe Blow",   # this works
        RANK() => "peon",       # this works
    );

But that is a comparatively rare occurrence compared with all the times you say $self->{ +NAME }, and a small price to pay.

Although the "member names" at the end in that object do not happen to conflict, it would not matter if they did, because it would be package-qualified into a different package.

Needless to say, you should only ever access your own private data members from within the class that declared them via use pluskeys, because doing so with some other class's is bound to get you talked about, and not in a good way.

The fact that

    $self->{ $self->COLUMN_MAP } 

kind of works (provided there are no conflicts) should not be taken as licence to use that sort of gross invasion of privacy. Always use the designated accessor methods for data members; don't go barging in where you're not at home.

SEE ALSO

The entire Fido class hierarchy uses this notation exclusively for dealing with its objects; this is critical when a final format object may have five or ten different unrelated mix-in classes in its ancestry. See Fido::Intro(3) for starters; then look into some of the many Fido classes, such as Fido::Data(3) for example.

Also see Class::Struct for the same idea. The package qualification is all based on an idea of Tom's from back in perl4 days, and it is still perfectly lovely today.

BUGS AND LIMITATIONS

Because constant is used, it is currently ill-advised to use non-ASCII identifiers.

AUTHOR

Tom Christiansen <tchrist@perl.com>

LICENCE AND COPYRIGHT

Copyright (c) 2005-2015, Tom Christiansen <tchrist@perl.com>. All Rights Reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.