Badger::Class

Thus Spake Andy:

The next level up above the class methods is the metaprogramming layer. This brings us to Badger::Class. This defines a class of objects which act as wrappers around Perl packages. Remember that a Perl package is the particular implementation of the OO concept of a class, and that packages are really just symbol tables. The terminology isn't that important as in most cases class is synonymous with package which is the same thing as a symbol table. But not quite.

A Badger::Class object allows you to set/get entries in the symbol table for a package (package variables, constants, methods, etc). It also provides higher-level metaprogramming methods. For example, there's a method to set the base class for a module which loads the module and adds it to @ISA (just like use base but implemented as a method rather than a separate module - less modules, faster startup).

Let me see if I can explain what I mean by hygienic class construction. Let's say you're writing a module and you need some accessor methods in your class. So you make Class::Accessor (or something similar) a base class of the module and then call the mk_accessors method to construct your accessor methods. Now modules like Class::Accessor quite rightly do one thing and do it well. But your module needs to do several things, so you add a bunch more base classes and call all of their respective methods to construct the other parts you need. The problem with this is that your module namespace has now been polluted by all of the methods that these modules implement. That includes all of the methods that you never used or required but got bundled in anyway. If two or more of the base classes implement the same method then you're in a world of pain. This might not even be obvious - for example, two of your base class modules could implement their own internal _error() method to report errors. Worse still, all of these class methods are also available as object methods. That means that every object you create will have a mk_accessors() method, which you almost certainly don't want. You can use namespace::clean to help you out of the mess, but that's really just addressing the symptoms and not the root cause.

The approach that Badger uses is to construct your new module class remotely. Instead of adding functionality to your class that you then invoke to have your module bootstrap itself, you create a Badger::Class object to do it for you from a distance. A Badger::Class object is a wrapper around your class's symbol table and implements methods to help manipulate the symbol table (e.g. to define methods, constants, package variables, etc). You can add as many different methods to the Badger::Class module (or a subclass of it) as you like because they never get added to the target symbol table. Hence, no pollution of your classes.