Code / The Appnel Group 

Posted
19 September 2007 @ 1pm

On Variable Scope

This post contains a lightly edited reply of mine that was posted to the mt-dev mailing list over a year ago. I thought I would pull it from the archives and highlight it again since scope is an important concern of developers when developing code that will run in persistent FastCGI.

Mark Carey wrote:

What is the best way to "limit the scope" of variables? And while I think I know what objects and methods (subroutines/functions?), I am less clear about what are Classes and "class data" and how to deal with the scope issues there.

To which I responded:

Scoping is a bit of a broad topic. Hopefully this example should help with the basics though. Take this class (in Perl this is a package that conforms to a few object-oriented programming principles):

  • package Some::Class;
  •  
  • my $class_data_persists;
  •  
  • sub new { bless {}, $_[0] }
  •  
  • sub set_object_data {
  • my ($object,$val) = @_;
  • $object->{value} = $val;
  • }
  •  
  • sub get_object_data {
  • my ($object) = @_;
  • return $object->{value}
  • }
  •  
  • sub set_class_data {
  • my ($this,$val) = @_;
  • $class_data_persists = $val;
  • }
  •  
  • sub get_class_data {
  • return $class_data_persists
  • }

In this example module (class) anything store in $class_data_persists will be shared by any object of Some::Class. So for instance.

  • use Some::Class;
  •  
  • my $x = Some::Class->new; # creates an object
  • my $y = Some::Class->new; # creates another object
  •  
  • $x->set_class_data('hello world!');
  •  
  • print $x->get_class_data; # prints hello world!
  • print $y->get_class_data; # also prints hello world!

Notice that $x and $y are objects of class Some::Class and that I stored the value 'hello world!' in $x and yet $y knew about it to output it when called. Since a persistent environment like FastCGI loads Some::Class once and leaves it in memory the value 'hello world!' will remain until the class is reloaded or overwritten with a new value. This simple value is not damaging, however it can easily be abused by storing large amount of data that consumes memory perhaps with data that has become "stale" (its been updated in the database). The worst case is when the class data keeps growing -- this is what is referred to as a memory leak. As the application runs it eats up more and more memory until the server comes to a crawl and finally crashes. This is a big issue in C programming, but less so in scripting languages like Perl which clean up memory that has gone out of scope. Perl still lets you leave variables and data in some long term or persistent scope which is what we are discussing here.

Back to our example to show some other types of scopes.

First I should note the $object variables in both set_object_data and get_object_data. To Perl, these are two totally different things despite having the same names. This is because each instance has a scope of their respective methods. The first time one of those methods is called, $object is set, the method continues and finally completes. Once it completes $object goes "out of scope" which means Perl removes it from its memory and frees up that space. The second time the method is called it has no knowledge of the value of the first $object or that it ever existed.

My example also has a type of scope which sits between the class and method scopes I've discussed. In set_object_data I place that value of $val in the object using $object-{value}>. As long as the object exists the value will remain in memory however that value is ONLY know to that object. For example.

  • use Some::Class;
  •  
  • my $x = Some::Class->new; # create an object
  • my $y = Some::Class->new; # create another
  •  
  • $x->set_object_data('hello world!');
  •  
  • print $x->get_object_data; # prints hello world!
  • print $y->get_object_data; # print undefined
  •  
  • $y->set_object_data('foo');
  •  
  • print $x->get_object_data; # still prints hello world!
  • print $y->get_object_data; # prints foo

If $x and $y were in a method, like $object and $val their value would be removed from memory when that method finishes running and the object and any data they contained along with it.

There are all types of ways you can screw up your scoping and unintentionally leave something in memory. For instance, if the object represented by $x above also gets stored in a class variable elsewhere it won't be removed from memory when the method finishes running because Perl knows it's (apparently) being used by the class and will keep it in memory in case its needed. Memory isn't freed up until all its references have gone out of scope.

Its a bit tricky to follow at first, but once you get the hang of it, it all becomes clear pretty quickly.

Hope that clarified some.



There are no comments yet. You could be the first!

Leave a Comment

← Before After →