How to read this crazy OO code

scrottie on 2007-07-29T09:41:47

Dear coworker,

I've done some things I'm not proud of. Going in to this relationship with me, you knew I had this weakness. Still, it doesn't make it right, so at least explain what is what, and why I did it.

More than anything else, I wanted to be able to move code without changing it around in any elaborate or error prone ways. At least to start with. Second to that, I wanted to break the pieces apart so they could be studied and changed in isolation, as well as plugged in as out as modules.

$a is a scalar. \$a is a reference to that scalar. Similarly, \%h is a reference to a hash. References are scalars. So you can store \%h in $a: $a = \$h.

When you call SomePackage->new(), it returns an object created out of a hash reference (it could be a reference to something else but I don't ever do that in this code). That gets stored in a variable: my $ob = SomePackage->new();

Then there's ->. Basically, -> means "indirectly through the reference". You can call functions indirectly, and you can access hashes and arrays indirectly through hash and array references. For now, I'm just going to use it to mean "call a function indirectly through an object or package". So SomePackage->new() calls the function new() indirectly through the package SomePackage.

$ob is reference to a hash, like \%h, except SomePackage's new() did somethings to associate it with SomePackage. Now you can do $ob->some_method() to call the function some_method() indirectly through $ob. That calls SomePackage::some_method() (probably, but there's inheritance and stuff that could change it). As one other special magic thing, it passes $ob in as the first argument, so $ob->some_method() winds up really meaning SomePackage::some_method($ob).

The code that got moved out of the main program got turned into an object. You do the $ob->method() thing to call functions (methods) in it. A method is just a function that hides behind an object. They're basically the same thing so don't worry about that now.

The code left in the main program did not get turned into an object, so you don't do the -> thing to call it. You just do main::function(). That's exactly like calling function() except it specifies to call it in that code rather than in the object.

Now, in the main program, there's a lot of code that looks like: *some_function = sub { ... };. That's rather than the usual: sub some_function { ... }. That's another form of Perl magic, and it's an extremely nice piece of magic that puts Perl in an elite class of languages that makes computer researchers at Universities like Perl. It also lets us solve hard design problems. The object needs to call functions in the main program, as above, like main::foo(). But those functions need to be able to see variables that are created and only exist deeply inside of another routine. sub { } without a name lets us make a new subroutine inside of another subroutine or code block and then we can do various things with it. To keep it simple, I'm just assigning it to a glob which makes it look like an ordinary subroutine. This way, we don't have to make the variables global. They exist where they already do, but in addition to that, part of the code inside there can be called later on from outside. It's really great. Just remember that we're naming part of the code in there and storing it for later to be called from elsewhere. This isn't considered evil or nasty, just advanced.

Here's something else strange that I did. The object doesn't have any methods in it, which is unusual, but I was being tricky. Instead, it has an AUTOLOAD method that gets called when any method in it gets called. Remember, that looks like $ob->some_method(). AUTOLOAD then runs. It calls code stored inside the object (specifically, stored in the hash reference the object is built out of). Don't worry too much about this except that the AUTOLOAD method runs and it uses the trick mentioned above, where subroutines are made on the fly.

That's all for now, I think. I hope...

Don't kill yourself.

-scott