NAME
Object::Variables - variables for objects
SYNOPSIS
The old way:
package Example;
sub new {
my $self = bless {}, shift;
$self->{foo} = 1;
$self->{bar} = [ qw(foo bar) ];
$self->{baz} = {};
return $self;
}
sub set_foo {
my ($self, $value) = @_;
$self->{foo} = $value;
}
sub foo {
my ($self) = @_;
$self->{foo};
}
sub method1 {
my ($self, $input) = @_;
$self->set_foo($input);
$self->{baz}{$self->{foo}} = 'huh?';
print $self->{bar}[$self->{foo}], "\n";
}
The new way:
package Example;
use Object::Variables qw(set: $foo noset: @bar %baz);
sub new {
my ($class) = @_;
my $self = $class->SUPER::new;
object vars : $self;
$foo = 1;
@bar = qw(foo bar);
return $self;
}
sub method1 {
my ($self, $input) = @_;
object vars;
$self->set_foo($input);
$baz{$foo} = 'huh?';
print $bar[$foo], "\n";
}
DESCRIPTION
One area where Perl's object-oriented features is less than stellar is its handling (or lack of handling) of instance variables. You can use fields
to create variables that are checked at compile time, but you still have to refer to each one as something like $self->{scalar}
, which is especially inconvenient with arrays and hashes...you might have an expression that has to be written as something like
$self->{hash}{$self->{key}}[$self->{index}]
which is cumbersome, to say the least. Object::Variables
lets you write that as
$hash{$key}[$index]
which is certainly easier to write and to figure out later.
In addition, you can specify that automatic accessor methods are to be created for some or all of the variables for the object.
This module is especially useful when combined with Sub::Declaration.
HOW IT WORKS
Declaration
You declare the variables you want to use by listing them in the arguments passed on the use
line. Include the leading "line noise" character so that the type of the variable is known...it will be initialized to a suitable default value when the object is constructed (undef for scalars, []
for arrays, and {}
for hashes).
Variable names beginning with _
are private, and aren't made accessible to subclasses.
You may also list any of the subroutines below that you wish to have available.
In addition, the following directives can be included in the list.
access-ro:
-
All variables after this word have accessor methods generated for them. The method name will be the same as the variable name minus the type character.
access-rw:
-
Like
access-ro:
, except that the generated method will set the variable's value if called with arguments. In that case it will return the prior value. noaccess:
-
Turns off both
access-ro:
andaccess-rw:
. set:
-
All variables after this word will have methods generated to set their values. The method name will be
set_
followed by the variable name. noset:
-
Turns off
set:
. strict:
-
If this occurs anywhere within the argument list, each method must explicitly name the variables it uses.
self:$name
-
Specifies that the name for the object reference will be $name. The default is
$self
(i.e.,self:$self
), but C++ fans might want to useself:$this
. (You can leave off the$
.)
Usage
You use the variables by including the following line at or near the beginning of each method:
object vars : $self (varlist);
where $self is the variable holding the object reference, and varlist is the list of variable names. You may omit the $self
part, in which case the object reference is taken to be $self (unless you've used the self directive). You may also omit the (varlist)
part, in which case all instance variables are made available (but this generates a fatal error if the "strict:" modifier was in the import list).
This directive has effect both at compile time and at runtime.
At compile time, it generates a my declaration for each instance variable that is used.
At run time, it links (aliases) these variables to the actual object field, taking inheritance into account.
That's it!
Implementation Details
Object::Variables
is implemented via a source filter in order to insert the appropriate variable declarations into the source code. See Filter::Simple for more information about source filters.
METHODS
This method is inherited by all classes that use Object::Variables
.
- new
-
$object = $class->new;
This is the object constructor. You must ensure that this is called, either by not defining your own new method, or by calling the superclass's method from within yours. It creates the variables, including those for superclasses, and sets up initial values.
The current implementation creates $object as an array, but you should not depend on this.
EXPORTABLE SUBROUTINES
- reference_to
-
$reference = Object::Variables::reference_to($object, $varname);
Returns a reference to the raw value for the specified variable. The raw value is the scalar contained in the underlying object array or hash: the scalar itself for scalar variables, or the appropriate reference for array or hash variables.
- pedigree
-
@list = pedigree($class);
Returns the list of ancestors to $class in the reverse order that Perl searches for methods, i.e., from the top down. The last entry in @list is $class.
DEBUGGING
If you are having a problem and need to see how Object::Variables
has processed your code, you can set the variable $Object::Variables::DEBUG
to a non-zero value. This causes the replaced program text to be sent to standard output after it is filtered. You need to do this in a BEGIN block:
BEGIN { $Object::Variables::DEBUG = 1 };
use Object::Variables qw(...);
RESTRICTIONS
Because of the way source filters work, the
object vars
directive will get replaced wherever it occurs. To prevent this from happening where you don't want it to happen (in a string or a comment, for example), just put a backslash in front of it, which will be removed. If for some reason you want the string "\object vars", use two backslashes.If you split a module over more than one source file, only the first module that gets compiled can contain variable declarations or directives; the others can only import routines. Why would you do this? The only case I can think of is a module that simply adds a method to another module. In that case, this restriction shouldn't be an issue...if you needed to add variables as well, you would create a subclass.
If you have two variables with the same name in different types, and create accessors for both of them, you'll only end up with an accessor for one of them. Since people don't generally create accessors for anything but scalars, this actually shouldn't arise much in practice.
MODULES USED
Lexical::Util (version 0.3 or later)
COPYRIGHT AND LICENSE
Copyright 2004 Kevin Michael Vail
This program is free software. It may be copied and/or redistributed under the same terms as Perl itself.
AUTHOR
Kevin Michael Vail <kevin@vaildc.net>