[Chicago-talk] Class::Accessor Revisited

Steven Lembark lembark at wrkhors.com
Fri Nov 28 14:59:30 CST 2003



-- Jay Strauss <me at heyjay.com>

> If I don't monkey with the internal structure like: $self->{key} = 'blah';
> How do I do stuff like:
>
> sub last {
>     my $self = shift;
>     $self->quote unless $self->{last};
>     return $self->{last};
> }
>
> that is if I want to do something in the accessor if the value hasn't been
> defined yet?  Or are you saying it's ok as long as I'm in the accessor,
> but don't do it outside the accessor?

One way to look at it: the whole point of an accessor -- or
mutator method for that matter -- is to encapsulate the
attribute being read/mangled. The method itself uses what it
knows about the data structure (say that the object is a
hash referent and uses the name "last" as a key) to manage
the data; outside the method all that should be known is
the method itself and its calling semantics.

Aside: you might want to modify the method above to ensure
that it is passed an object and die with a more informative
message if called improperly. For example adding an
"or die, missing object" could save a lot of debugging.

If the quote method returns whatever it manipulates then
the item above could be written:

	sub last
	{
		# grab whatever it is and make sure its both true and
		# a referent. using "$self->isa( __PACKAGE__ )" every
		# time through gets expensive, however.

		my $item = shift
			or croak "Bogus last: no arguments";

		ref $item or croak "Bougs last: requires an object";

		# at this point it's likely you at least have an
		# object. if object has a "last" entry then return
		# it, otherwise pass the request off to the quote
		# method and hand back whatever it comes up with.

		$item->{last} or $item->quote
	}

the quote method would then be written to handle quoting,
whatever that does.

The only problem here is that you may get into the situation
where the quote method has to know about a last entry unless
last takes an extra argument to act as an initializer. If you
REALLY want to encapsulate last then the method might look
like:

	sub last
	{
		my $item = shift;

		ref $item or croak "Bogus last: requires an object";

		if( @_ )
		{
			# this assumes that last items can be overwritten.
			# if not then use $item->{last} ||= shift -- which
			# hands back the unmolested current value or just
			# croak "Cannot overwrite $item->{last} with $_[0]"
			#  if $item->{last};

			print "Overwriting: $item->{last} with $_[0]"
				if $verbose && $item->{last};

			# caller gets back the current last value in any case.

			$item->{last} = shift
		}
		else
		{
			# hand back the last entry or whatever quote thinks
			# is appropriate.

			$item->{last} || $item->quote
		}
	}


With this setup $item->quote can call $item->last( $new_last_value )
to set the new value in $item->{last} without having to know where/how
the value is stored and updated. This puts all knowlege of the "last"
value within the last method.

--
Steven Lembark                               2930 W. Palmer
Workhorse Computing                       Chicago, IL 60647
                                            +1 888 359 3508



More information about the Chicago-talk mailing list