|No such thing as a small change|
In praise of Perl's object system.by DStaal (Chaplain)
|on Sep 08, 2010 at 19:39 UTC||Need Help??|
I was thinking about an old node of mine the other day, and got to pondering Perl's object system in general. I came to the conclusion that it's much better than it gets spoken of.
Most people coming to Perl's object system have already done object-oriented programming in one or more other languages. They know how it works, and what objects are. A typical thought on what an object is probably is something like this:
An object is a set of functions that know what data they are to operate on.
This is a decent, usable, understanding of what an object is. It is also subtly wrong. An object is:
An object is a set of data that knows what functions operate on it.
The difference is subtle, but quite important for understanding objects in Perl. In most languages, you get a set of dedicated grammar for defining the object, the data that is in it, and the functions that are related to it. Perl has cut these to an absolute minimum. In fact, Perl gets by with just a handful of words, and one new calling syntax:
And the syntax: (I'm ignoring indirect syntax, as generally a bad idea.)
$foo->bar(); # The same as: 'bar($foo);' in the package $foo is blessed into.
That, for all normal intents and purposes, is it. (I could be missing something. Also, SUPER might be usable outside an object.) Everything that other languages do with private, public, property, etc. are all done using the above and other already existing features of the Perl language.
The most important one, and the one where that subtly-wrong definition will bite you, is bless(). It marks a reference to a set of data as being of an object. The functions that operate on this data are the functions in a specific package. (Defaulting, of course, to the current package.)
Note that Perl's packages are used for other things: They are the normal way to group related functions together. They can be used to limit scope, or to help organize code. Many many modules simply export functions from their own package into the calling package upon demand. So that grouping is not part of Perl's object system. It is part of Perl.
Also, there is no imposed structure on the reference that has been blessed. It can be any reference, of any type, and can be as complicated as you want it to be. (I haven't actually tried bless()ing a code reference, but I suspect it would work...) Perl allows references to point to structures that contain other references, so you can have arbitrary complexity, if you want it. You can also use that reference as a key into some other data structure(s), allowing for even more options.
This leads to some simple points: If the reference is directly to the data, then anyone can access that data through that reference. This is the same as 'public' data in many other languages. (With the same pros and cons.) If data is accessed via using the reference as a key into some other data structure, then the data is as private as that data structure. It can be 'protected' or 'private', as the case depends. Since the reference can contain data structures, the actual data can be stored in ways that allow all of the above, within a single class. All of this with one word of syntax, and the data storage techniques you already know!
Which brings the next point: Some of that data might be more important that other data. Or larger, harder to access, or need to be accessed more often, or... This isn't a problem for Perl, because object data is handled using the same tools as any other data. You need it done one way? Do it that way. You have the whole language to work with.
This 'object data is regular data, just marked as part of an object' extends into the one real syntax: the calling syntax. All it really does is say which package to look in for the function, and implies that the function gets one extra piece of data, your reference.
So, object functions are regular functions. You can even call them as regular functions, if you pass them the correctly-structured arguments.
There is no conceptual difference, in Perl, between anything that is an object, and anything that isn't. Data is data. Functions are functions. The programmer is free to do what they like with them. Objects are a way to organize code.
You want a singleton object? Just return the same data reference every time. You want a pool of objects? Keep a group of references, and alternate between them as you want. You want people to be able to access your data directly? Give it to them in the reference. You want to protect it? Have the reference point to a key for another data structure, that you keep hidden.
You want to be able to string object method calls to infinity? Ok, have them return their blessed reference. You want easy mutators for specific data elements? Simple enough to write.
Once I started to think about it, I realized the 'cryptic' OO-system in Perl isn't cryptic at all. It is just enough to make sure you can do anything you want, and nothing to get in your way.
It's beautiful. It's simple. It's powerful. It's Perlish.