=pod

=head1 NAME

Package::Transporter - encourages the use of constant functions


=head1 SYNOPSIS

The following example demonstrates the creation and use of the
constant functions ATB_NAME, ..., ATB_PRICE. The creation is done
inside the BEGIN block, which should make clear that Package::Transporter
is about compile-time.

	package CF3;
	use strict;

	use Package::Transporter sub{eval shift}, 'mix_in:*';
	BEGIN {
		Package::Transporter->new()
		->array_indices('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 through the
mix_in:*.


=head1 WARNING

This is the first public release of Package::Transporter. The module hasn't
been throughly tested, making the probability of fatal bugs quiet
high. If you want to use Package::Transporter in a production environment,
which is not recommended at the current stage, then you would
certainly need heavy additional testing on your side to protect you
from the effect of bugs. The main purpose of the release is to open
the stage for comments early. 

In addition to the stage of the development, be warned that
Package::Transporter is a workaround. It overcomes the lack of full OO
support in Perl5, meaning identifier management for methods plus
attributes. With Perl6 or any modern language, Package::Transporter
has little point. If you plan to switch to Perl6 soon, then
Package::Transporter is definitely not for you.


=head1 DESCRIPTION

The objective of Package::Transporter 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.

Package::Transporter generates Perl code based on very simple rules defined by
the programmer. The generated code is added to modules via an
explicitly declared visit point.


=head2 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. This is a general
recommendation and independant of the scope or propagation of a
name. 

Package::Transporter supports a prefix for most symbol operations,
so that they can be specified in a concise way.


=head2 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 I<are on sale> and there is an I<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};
	BEGIN {
		Package::Transporter->new()
		->class_constants('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};
	BEGIN {
		my $pkg = Package::Transporter->new();
		$pkg->random_values('ATB_', [], qw(NAME  TYPE  STOCK  PRICE));
		$pkg->application('constant_function', [], 'ATB_');
	}

	#...
	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.


=head2 Performance Potential

Arrays are slightly faster and require less memory than hashes in
perl5. Package::Transporter makes it attractive to implement objects
via array references.

However, it should be noted that constant functions do have a
performance impact, because they use up additional memory and defining
them also takes time during compilation of the perl
program. Undefining constant functions returns some of the memory
allocated for them.

Is it really worth to think about performance? Sometimes Moore's Law
is used as a general justification of resource intensive strategies,
which is, like general statements in general, not really
convincing. The computer market is more diverse nowadays, with a big
market for low performance devices. Moore's Law doesn't take market
shares into account. Even if you restrict your view to server
machines, their performance is countered by higher demands. More
users, more services, more convenience. Again, resource intensive
strategies have no general justification and if there are options for
improved performance, it makes sense to at least consider them.


=head2 Relations

To leave no doubt, Package::Transporter isn't designed to replace Exporter and
cannot be used as a drop-in replacement.

Package::Transporter is similar to Exporter with regards to sharing.  Both
enable a module to share identifiers with another module. However, the
goals and implementations differ. Exporter keeps creation and sharing
separate, so that the programmer has extra work in keeping them in
sync. Exporter is a small generic solution, which uses direct symbol
table manipulations for efficiency. Package::Transporter is bigger in terms of
amount of code and functions provided. With Package::Transporter, the symbol
table is manipulated indirectly at defined visit points. It aims at
automated creation and automatically synchronized sharing. Package::Transporter
can deal with lexically scoped and state variables, although in a very
limited way.

Like source code filters, Package::Transporter generates perl code. However,
source code filters are active before BEGIN, while Package::Transporter becomes
alive at or after BEGIN. A source code filter is intended to create a full
Perl module. Package::Transporter only complements modules at visit points.

The 'constant' module is a special case of Package::Transporter with
constant_function applied. One example in its man page really calls
for more compactness (and for the prefix !!!!!!!), which can be
provided via Package::Transporter (see example RELCON1 below).

	package RELCON1;
	use strict;

	use Package::Transporter sub{eval shift};
	BEGIN {
		my $pkg = Package::Transporter->new();
		$pkg->array_indices('T_', [],
			qw(SEC MIN HOUR MDAY MON YEAR WDAY YDAY ISDST));
	}

=head1 USAGE

When you activate the Package::Transporter module through the
statement 'use', pass a package visiting point as a parameter. Meaning
the somewhat funny anonymous subroutine sub{eval shift}. Optionally
you can specify which applications from other packages to mix in and
mix_in:* is a normal choice.

	use Package::Transporter sub{eval shift}, 'mix_in:*';

All actions of Package::Transporter refer to the visiting point. You
can re-define the visiting point of a package by passing such a
subroutine to the constructor again, like in

	my $pkg = Package::Transporter->new(sub{eval shift});

Remember that the new method returns an object of class
Package::Transporter::Package, therefore the variable name
$pkg. Applications and their symbols can be shared between
packages. Example:

	package CF5;
	use strict;
	use Package::Transporter sub{eval shift};

	BEGIN {
		my $pkg = Package::Transporter->new();
		$pkg->package_constants('IS_', 'TRUE' => 1, 'FALSE' => 0);
	}

	package CF6;
	use Package::Transporter sub{eval shift}, 'mix_in:CF5';

	die() if (IS_TRUE == IS_FALSE);

Further details on the usage can be found in the documentation for the
package Package::Transporter::Package.

=head2 Mix Ins

The optional second argument in the use statement specifies the mix
with other packages. Only such external applications are mixed in, which have
the properties SCP_PUBLIC and MIX_IMPLICIT set.

=over 8

=item * B<mix from main> - the default; no second parameter; always done

=item * B<mix along @ISA> - selected with 'mix_in:isa'; search through @ISA (the array maintained via 'use base') for packages using Transporter

=item * B<mix along hierarchy> - selected with 'mix_in:hierarchy'; search through the own package name for other packages using Transporter; package A:B:C will attempt to mix in from A:B and A.

=item * B<all of the above> - selected with 'mix_in:*'

=back

If you don't want to mix at all, then don't pass the visiting point
as the first argument in the use statement.


=head1 CONCEPT

Package::Transporter modifies a module at an explicitly defined visit point,
which is set through the anonymous subroutine sub{eval shift}. The
implementation of your symbol is submitted as a text and brought to
life by the eval. Notice that any variable declaration via 'my' or 'state'
after the visit point won't be visible to your symbol
implementation. Declarations via 'our' and subroutine declarations are
global and therefore fully accessible anytime anywhere.

A visit point is slightly more powerful and cleaner than a direct
symbol table manipulation. It enables you to use a well defined
interface instead of relying on implementation details. The 'sub'
keyword isn't pure luxury on top of a 'flexible and powerful symbol
table', but a product of intelligence on top of raw force.

The default visit point should be the loading of the Package::Transporter
module via use, but that isn't enforced. Upon loading, Package::Transporter
will create an object for the calling package to store package details
like the visit point. The object is monadic within a package and of
type Package::Transporter::Package. Meaning that 'Package::Transporter->new' won't give
you a fresh object, but rather the one belonging to the current
package.

With the package object, you can basically do three things:

=over 8

=item * B<create symbols> - Varying method names. The goal is to use rules for automatic creation. Available rules are defined in module files of the class Package::Transporter::Symbol::*.

=item * B<apply symbols> - Fixed method name 'application', with the actual method name to use as a first parameter. Available applications are defined in module files of the class Package::Transporter::Application::*.

=item * B<above combined> - in other words: convenience functions.

=back

To create a symbol just involves a name and a value. It stays a theoretic construct, meaning your module won't see it. See what?! Package::Transporter can turn it into a managed attribute, a constant function or anything else you write a module for. The application of a symbol can be adopted to your needs.


=head2 Convenience Functions



=head2 Debugging

Set Package::Transporter::DEBUG=1 to activate the debugging aid
package_vs_file_name. It will then check the package name against the
package file name.


=head1 PUBLIC INTERFACE REFERENCE

Only the public interface is documented in the following.

=over 8

=item B<new>

The constructor. Calling parameters: package visiting point (subroutine reference). Return value: a Package::Transporter::Package object.

=item B<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.


=head1 KNOWN BUGS AND LIMITATIONS

This is the first public release.

Transporter stores data in package attributes, which aren't covered when you serialize an object with Data::Dumper or similar tools. With regards to its own data, persistence isn't a concept built into Transporter. The data of Transporter is considered a temporary affair of the compilation phase, although you are free to use it afterwards.

Perl objects implemented via array references can be serialized and loaded later as long as the structure of the attributes doesn't change. Note that the enumeration of attributes is done in the order their names are given. If you change the order, you change the structure. Even appending a new name at the end of the existing attributes might change the structure, because it changes enumeration in derived classes. This limitation is highlighted, because Perl objects are traditionally implemented as hash references.


=head2 WISHLIST

The author hopes that one day there will be a 'use stricter'. Which
does, among other things:

=over 8

=item * Make its effect irreversible. Meaning there is no 'no stricter'.

=item * Introduce 2 as irreversible flag in Internals::SvREADONLY(..., 2); with the purpose of locking the readonly flag.

=item * Let Internals::SvREADONLY also prohibt re-blessing a locked reference, re-declaring a package namespace and re-defining a subroutine.

=item * 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.

=item * Make the namespace of a package read-only for other packages. (Indirect access to the symbol table via '::' is read-only.).

=item * Disable direct access to the symbol table. No \*, no \%::. Or at least restricted to the current package.

=item * Let 'package' return a reference to or name of the namespace.

=back


=head1 AUTHOR

Winfried Trumper E<lt>pub+perl(a)wt.tuxomania.netE<gt>


=head1 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.


=head1 SEE ALSO

The manual page for L<Package::Transporter::Package> contains the details
of using and extending Package::Transporter.

Different approaches are provided by the Perl modules L<Exporter> and L<constant>.

The following packages provide support for objects as array references and are therefore loosely related to Transporter: L<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: 
L<List::oo>, 
L<Class-Builtin>, 
L<Devel-Ladybug>, and
L<Object-Array>.

=cut
