NAME
Package::Transporter::Generator::Constant_Function - base class for generating constant functions at compile time
SYNOPSIS
The following example demonstrates the creation and use of the constant functions ATB_NAME, ..., ATB_PRICE.
package CF3;
use strict;
use Package::Transporter sub{eval shift}, sub {
$_[0]->register_drain('::Enumerated', 'FOR_SELF', 'ATB_',
qw(NAME SALE STOCK PRICE));
};
#...
sub sell {
my ($self, $amount) = @_;
# return if (ABT_SALE == IS_FALSE);
$self->[ATB_STOCK] -= $amount;
my $costs = $amount * $self->[ATB_PRICH];
return($costs);
}
Perl will tell you at compile time about the typing mistake ATB_PRICH, which could be seen as the main motivation for the exercise. The generated symbols can be inherited by other packages, therefore completing the OO system of Perl. The symbol IS_FALSE is such an example, it comes from a imaginary upstream package.
DESCRIPTION
The objective of this class is to promote a greater expressiveness of Perl5 code, while keeping fundamental programming practices intact. Practically this is achieved through constant functions, which are managed in a convenient manner. For details on constant functions, see the manual page perlsub. In short, such functions result in an inlined value, meaning that no actual subroutine call is performed by perl.
The class forms the base for ::Enumerated_CF, ::Random_CF, ::Lowered_CF, and ::Flatened_CF.
Motivation
Hashes are a popular approach to store information in Perl. Their keys are based on scalar strings, which opens the door for typing mistakes. Perl can't tell you about the typing mistake IS_OM_SALE in package CF0 (see below) at compile time. With Hash::Util you can set a trigger for a fatal exception once the erroneous code is executed, but that is unpredictable - maybe it never happens - and really late compared to the trivial nature of the error.
# -- common approach using strings (without Package::Transporter)
package CF0;
use strict;
my $states = { 'IS_ON_SALE' => 1 };
my $apples = $states->{'IS_OM_SALE'};
my $oranges = 1; # two times faster than apples
The example package CF1 (see below) demonstrates the creation and use of the constant function IS_ON_SALE. Oh, again a typing mistake. Good that IS_ON_SALE is an identifier and not a string, so Perl will tell you at compile time about the unknown identifier IS_OM_SALE. That is favorable over the case where the customer reports the error to you after the whole show crashed.
# -- manually crafted constant function (without Package::Transporter)
package CF1;
use strict;
sub IS_ON_SALE() { 1 };
my $apples = IS_OM_SALE;
my $oranges = 1; # same execution speed as apples
After the assignments to $apples and $oranges, both variables hold the same value "1". Because of internal optimizations in perl, there is even no impact on execution speed by using IS_ON_SALE. However, the expressiveness is higher. From reading the source it is clear that $apples are on sale and there is an amount of one orange left (in the basket). The technique to use symbols instead of actual values is even older than Perl, but not commonly found in Perl.
package CF2;
use strict;
use Package::Transporter sub{eval shift}, sub {
$_[0]->register_drain('::Flatened', 'FOR_SELF', 'IS_',
'ON_SALE' => 1);
};
my $apples = IS_ON_SALE;
my $oranges = 1;
The example package CF2 (see above) demonstrates how to create the constant function with Package::Transporter. Regarding the amount of code required, the use of Package::Transporter is not efficient for trivial cases. Remember that the examples CF0, CF1, and CF2 are about the general motivation for constant functions, not about the motivation to use Package::Transporter.
Now that you are hopefully convinced about constant functions, you want to use them all over the place. How about random hash keys for your objects? Annoy all the people who mess around with the internals of your objects:
package CF4;
use strict;
use Package::Transporter sub{eval shift}, sub {
$_[0]->register_drain('::Random', 'FOR_SELF', 'ATB_',
qw(NAME TYPE STOCK PRICE));
};
#...
sub sell {
my ($self, $amount) = @_;
$self->{+ATB_STOCK} -= $amount;
my $costs = $amount * $self->{+ATB_PRICE};
return($costs);
}
Inconsistencies in 'use strict' enforce a unary plus in front of the subroutine identifiers ATB_STOCK and ATB_PRICE. Without the plus, the identifiers would surprisingly be taken as unquoted strings. It is surprising, because it is the opposite of what 'use strict' was meant for. Fixed in Perl6.
To end this section and to do what its title implies, namely to motivate you, it should be mentioned that symbolic array indices can be shared between packages in a way that is called inheritance in the OO world.
The Prefix
This package can easily lead to many symbols being used, thus potentially increasing the chance of name clashes. Meaning that a name is allocated for conflicting purposes. You can protect from such clashes by using a meaningful prefix. Example: IMAP_CST_ as prefix for DISCONNECTED, to indicate that the symbol IMAP_CST_DISCONNECTED is about a disconnected IMAP client state.
PUBLIC INTERFACE REFERENCE
Only the public interface is documented in the following.
- new
-
The constructor. Calling parameters: package visiting point (subroutine reference). Return value: a Package::Transporter::Package object.
- drop
-
The sweeper. Removes the object from the Package::Transporter class with the intention of releasing the allocated memory. No calling parameter or return value.
KNOWN BUGS AND LIMITATIONS
WISHLIST
The author hopes that one day there will be a 'use stricter'. Which does, among other things:
Make its effect irreversible. Meaning there is no 'no stricter'.
Introduce 2 as irreversible flag in Internals::SvREADONLY(..., 2); with the purpose of locking the readonly flag.
Let Internals::SvREADONLY also prohibt re-blessing a locked reference, re-declaring a package namespace and re-defining a subroutine.
Complain about the unqouted string in { key => 'value' }. Yes, there is an unqouted string and it should be treated as such. Or at least give precedence to constant functions.
Make the namespace of a package read-only for other packages. (Indirect access to the symbol table via '::' is read-only.).
Disable direct access to the symbol table. No \*, no \%::. Or at least restricted to the current package.
Let 'package' return a reference to or name of the namespace.
AUTHOR
Winfried Trumper <pub+perl(a)wt.tuxomania.net>
COPYRIGHT
Copyright (C) 2009, 2010 Winfried Trumper
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
SEE ALSO
The manual page for Package::Transporter::Package contains the details of using and extending Package::Transporter.
Different approaches are provided by the Perl modules Exporter and constant.
The following packages provide support for objects as array references and are therefore loosely related to Transporter: Class-Gomor (there are more, but I can't find them right now).
The following packages treat arrays as objects, which Transporter is not about, but that also clarifies things: List::oo, Class-Builtin, Devel-Ladybug, and Object-Array.
The package POE is features a lot of constant functions
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 171:
You forgot a '=back' before '=head1'