The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

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;
            use object vars : $self;
            $foo = 1;
            @bar = qw(foo bar);
            return $self;
        }

        sub method1 {
            my ($self, $input) = @_;
            use 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: and access-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 use self:$this. (You can leave off the $.)

Usage

You use the variables by including the following line at or near the beginning of each method:

use 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).

(For backward compatibility with earlier versions of this module, you may leave off the word "use", but this is deprecated.)

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 use 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 actually want the string "\use 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 REQUIRED

Tie::IxHash, Filter::Simple, Lexical::Util (version 0.8 or later)

SEE ALSO

Perl6::Binding, Lexical::Alias, fields

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 <kvail@cpan.org>