| Package-Transporter documentation | view source | Contained in the Package-Transporter distribution. |
Package::Transporter::Generator::Drain::Constant_Function - Base class for generating constant functions
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.
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.
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.
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.
Only the public interface is documented in the following.
The constructor. Calling parameters: package visiting point (subroutine reference). Return value: a Package::Transporter::Standard object.
The sweeper. Removes the object from the Package::Transporter class with the intention of releasing the allocated memory. No calling parameter or return value.
The author hopes that one day there will be a 'use stricter'. Which does, among other things:
Winfried Trumper <pub+perl(a)wt.tuxomania.net>
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.
The manual page for Package::Transporter contains the details of using and extending Package::Transporter.
The package POE is features a lot of constant functions
| Package-Transporter documentation | view source | Contained in the Package-Transporter distribution. |