Do you know where your variables are? | |
PerlMonks |
Anyway, implemented as hash references, it's difficult to really protect your data. But if you implement your object as a closure, you can protect your data as much as you'd like! This method is described in perltoot, and it's pretty neat.
Up until here, everything looks normal: you've declared a package "Person", and you've started to create a constructor; you determine the class that this object will be bless'ed into; and you set up the data fields. A person will have a name and an age.package Person; use strict; sub new { my $type = shift; my $class = ref $type || $type; my $self = { NAME => undef, AGE => undef };
If we were implementing our object as a hash reference, we'd bless $self into $class and be done with it. But that would let any user of our object mess with NAME and AGE directly, rather than through our accessor methods.
So, instead of a hash reference, we implement the object as a closure. A closure is a subroutine reference that has access to the lexical variables that were in scope when it was created. So, in this case, we're most concerned with our closure being able to access the fields in $self.
The closure will be an anonymous subroutine that will act as an accessor/setter method. We'll give it a field name (NAME or AGE), and a possible second argument (a value to set that field to), and it will return the value of the field. So let's implement that:
Pretty simple: the closure takes a field, sets the field if it's given a value, and returns the value either way.my $closure = sub { my $field = shift; @_ and $self->{$field} = shift; $self->{$field}; };
Now the magic: we're going to bless our closure into $class so that the closure *is* the object!
We create a new closure object, blessing it into $class, and return it; and we're done.bless $closure, $class; $closure; }
As mentioned, these receive the closure (a code reference) as the zeroth argument, so they invoke that code reference. The arguments they provide are the field name ("NAME" or "AGE"), and then a list of any other arguments that were handed to them.sub name { &{ $_[0] }("NAME", @_[1 .. $#_ ] ) } sub age { &{ $_[0] }("AGE", @_[1 .. $#_ ] ) }
Thus, what happens is that the closure (which, remember, has access to our data fields via $self) gets the name of the field, sets the value of the field if a value is provided, then returns the value.
use strict; use Person; my $person = new Person; $person->name("Foo Bar"); $person->age(22); print $person->name, " is ", $person->age, " years old.\n";
For example, you could define a new data field (called "PRIVATE", for example)--and if you didn't define an accessor method, the user would have no way of accessing that field. In your implementation, however, you could access it as much as you wished (although you'd have to go through the closure to do so).
Which, I think, is pretty neat.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Objects with Private Variables
by runrig (Abbot) on Mar 30, 2003 at 17:26 UTC | |
by Excalibor (Pilgrim) on Jul 08, 2003 at 09:27 UTC | |
by misterb101 (Sexton) on Jun 07, 2005 at 09:36 UTC | |
by jbrugger (Parson) on Jun 08, 2005 at 07:10 UTC | |
by akr8986 (Initiate) on Dec 18, 2015 at 11:37 UTC | |
by Anonymous Monk on Dec 18, 2015 at 16:19 UTC | |
Re: Objects with Private Variables
by Anonymous Monk on Mar 30, 2003 at 16:21 UTC | |
by diotalevi (Canon) on Mar 30, 2003 at 17:10 UTC | |
Re: Objects with Private Variables
by zby (Vicar) on Mar 27, 2008 at 10:34 UTC |