perlsOfLondon

 

Intro to Object Oriented Programming

Page history last edited by dmlond 3 yrs ago

From the very beginning, programmers found themselves dealing with data that either already had a defined organization, or wanted to be organized in some way, e.g. something like a sequence entry, with a sequence id, and a set of related pieces of data (the sequence, its strandedness, its start and end coordinate, etc.). In earlier programming languages like fortran, you would handle these things using lots of arrays, and hashing functions which, when given a particular sequence id, could give you the position within an array for a particular desired attribute of the sequence. Then you would have to write functions for manipulating sequence related data using these hashing functions, and all the arrays separately. In the end, even the best programmers found their data, and their code spread out all over their application code. This was very hard to maintain. Later on the C programming language was designed to handle this type of data a little better, using something called a struct. This was a way of packaging a discreet group of data around a particular focal data point into a single data reference which could be assigned to a variable. This could then be passed around the program, and the attributes of the data could be accessed/manipulated in a programatic fashion. This was a major step towards OO programming, but you still had the problem of where to place the methods for manipulating these structs. Furthermore, most programmers already had started to classify these structs, and make special packages of methods for dealing with different classes of structs. You might have a library for dealing with the struct that contained a genbank record, and a different package of methods for manipulating a struct containing a fasta record. This grated on their laziness nerve. Wouldnt it be nice to have the methods for manipulating these classes of structs packaged with the struct data variables themselves? Thus were born a slew of languages designed to support this new, Object Oriented way of programming. I also think there was a certain jealousy among Computer Science faculty toward their philosophy colleagues, who always seemed to get the best dates. Thinking about Objects allowed them to wax philosophical a little themselves. They could talk about Plato. Plato believed in the existence of archetypal essences, or classes, and that each individual object in the world was an instance of this Platonic form. Computer scientists could analogize this to classes, which could have multiple instances, which were instantiated (or constructed) at runtime with different groups of data. Furthermore, each object would have all of the methods for manipulating them, or allowing them to interact with other types (classes) of objects, packaged along with them. Thus, you could have a seq object instance of type Sequence, which had sequence, length, start, and end attributes, and revearse-transcribe, truncate, splice, insert, etc. methods. You could ask whether seq->equals(seq2). You could seq->insert(seq2, 0, seq2->length). This proved to be a very efficient way of writing programs. Not only could you keep the data variables with the methods and accessors within the same physical code file, you could also start to do things like separate the methods for manipulating these objects from the underlying code for doing the manipulation. You might have a matches method which takes another Sequence object and compares its sequence to this other objects sequence using a WashU blast call. This might work well for everyone who uses your code, but you might, at some point want to change the method to use blat, instead. As long as you dont change the name of the method, or its signature (the arguments, and their order), no one else has to change their code in order to continue using your object (unless they just particularly liked the WashU way of finding a match, in which they would have to use an earlier version, or write their own code). This type of programming proved to be and extremely flexible way of managing large programming tasks with lots of different data structures to manipulate. That being said, it is probably best, when you do decide to start using, or even writing, objects, to remember the other aspect of Plato's philosophy. You see, not only did Plato subscribe to this idea that all objects were instances of some class, he believed they were __INFERIOR__ instances; they were always missing something, had some flaw, some imperfection which spoiled them when viewed in the light of what they could be. Defensive programming is always prudent.

Now, having said all that, I must let you in on a little secret. Perl doesnt actually support objects. It was written as a procedural language, and had OO programming hacked onto it. Basically, Damian Conway realized that perl could very easily support OO style, with a minimal burden on the programmers. What he did was the following. In perl, you can call the name of a method within another package like so (regardless of whether it is OO or procedural):

my $out = SOME::Package::someMethod(@args);

What Damian did was hack the source lexer of the perl interpreter to recognize the following call, as well:

my$out = SOME::Package->someMethod(@args);

Furthermore, it was designed to do something special with this type of call, it passed the Package name as a string as the first argument to the method. This did place an extra burden on the programmer to handle this argument, but it got us most of the way to OO. The other thing the programmer had to do was use the bless function to bless some regular perl variable (hash, array, scalar, references, TypeGlobs) as a symbol of the Package name passed as this argument. Thus, somewhere in any perl Object code, you will see something like the following (note, it is standard practice to name your constructor method 'new', but it doesnt have to be this way, also most objects use a hashref, or arrayref, named $self, but this is just a convention, it isnt enforced as a rule):

sub new {
  my ($class, @args) = @_;
  my $self = bless {}, $class;
  #do something with @args, if any, using the $self variable to store them either as items in the array, or values with a specific key, etc
  return $self;
}

You can preload this array, or hash with any data you want before calling bless on it

sub new {
  my ($class, @args) = @_;
  my $self = { 'somekey => $arg[0] };
  bless $self, $class;
  #do something with @args, if any
  return $self;
}

or load it after the bless. It is just like any other reference you have used before. However, now when you dereference a method from that object, because it is blessed, the lexer can, again, look to see what its package name is, and call that method from the package. Furthermore, it will pass the reference (with any data inside of it) as the first argument to the method. Again, this makes a little extra burden on the programmer to handle this extra argument, before handling the real arguments they pass in. Java doesnt make the programmer do this, Python goes half way between the two. Thus, an OO method in perl will look something like:

sub someMethod {
  my ($self, $arg1, $arg2) = @_;
  my $ret = $self->{'somekey'};
  return "$ret is $arg1 AND $arg2";
}

And is called simply by using:

$refObj->someMethod(@args);

Lets take a moment to decompose this a bit:
Perl takes this:

my $refObj = SOME::Package->new();

And magically turns it into this:

my $refObj = SOME::Package::new("SOME::Package");

Once you have a reference to something blessed to "SOME::Package", perl will honor the following dereference of someMethod:

$someObjRef->someMethod(@args);

by turning it magically into this:

SOME::Package::someMethod($someObjRef, @args);

The reason I say this is merely to explain why you need to handle the input parameters to OO methods in perl the way you do. Its because perl achieves OO programming style, where you place the methods for manipulating the data in the same package as the data, using a common-law-marriage arrangement, instead of requiring a preacher to seal the deal the way other OO languages do, that perl has these features (quirks). By the way, one other thing that comes as a side effect of the way the perl lexer handles this for you is that perl OO modules do not have to use Exporter, or specify which methods, variables, etc are going to be exported. You simply write the modules methods, and the perl interpreter takes care of the rest.

Comments (0)

You don't have permission to comment on this page.