Here in the monastary, I have seen (and participated in) many a discussion about the pros and cons of perl's OO system. In particular hash-based OO and the evils of autovivification and key mis-spellings. I have seen Abigail-II's inside-out objects as one solution, but to be honest I don't like them (no offense Abigail-II they are just not my style). I have looked over some of the automated class builders out there, but I didn't like them either (again, no offense to the authors). In the end I liked good old hash-based perl OO and so I resigned to just use self-discipline and company coding standards to enforce good OO citizenship.
A while ago I asked a question of the monastery Has anyone ever really used Tie::SecureHash?, and I got no responses. I asked if anyone has ever actually used Tie::SecureHash, in particular as a debugging tool. Apparently no one had. It had occurred to me that object field access controls in other languages (Java, C++, C#, etc.) was something that was very nice to have, but once you completed your program, that information served (mostly) no purpose but to just enforce something you were already complying with anyway. I saw then the possibility of using something like Tie::SecureHash as both a debugging and validation tool, as opposed to actually using it in my implementation. Tie::SecureHash itself discourages its own use in production and incorporates a "fast" mode where-by you can just turn if off, but not have to remove it from your code.
So I tried it out, and after incorporating Tie::SecureHash into a few toy modules, I realized that there was little chance at all that I would spend my time incorporating it into any existing production code (especially just for debugging). The idea of changing that much code was incredibly unappealing to me, and something I could not justify the time/money for. So my next thought was to hack CORE::GLOBAL::bless to sneak in and use Tie::SecureHash, this worked up until I loaded modules that were not my own, and BOOM!. It was not pretty. It also occurred to me that Tie::SecureHash's access controls were not very flexible, I had to change my code again, prefix '_' for protected, and prefix '__' for private. I never use '__', I only really used '_' for private.
So as you may have guessed, I decided to re-invent the wheel. Well, sorta re-invent the wheel, because no matter how good TheDamian is, and how cool Tie::SecureHash is, it didn't suit my needs, and there was no way to shoehorn it to do so. So I created Devel::StrictObjectHash.
Here is some example code:
# do nothing use Devel::StrictObjectHash; # replace CORE::GLOBAL::bless (not really recommended) use Devel::StrictObjectHash strict_bless => 'global'; # turn on debugging use Devel::StrictObjectHash debug => 1; # turn on both use Devel::StrictObjectHash ( strict_bless => 'global', debug => 1 ); # replace bless in these modules only use Devel::StrictObjectHash ( strict_bless => [ qw(MyModule HisModule HerModule) + ] ); # allow auto-vivification in routines other than 'new' # as a string use Devel::StrictObjectHash ( allow_autovivification_in => "_init" ); # as a reg_ex use Devel::StrictObjectHash ( allow_autovivification_in => qr/create_.*|_init/ );
You use the module by loading it at the top of you script or in your mod_perl startup.pl file and configure it to your needs. It then watches your code for OO badness. One thing to note, currently it does not allow public fields at all. Meaning, there is no hash access outside of the object. This is good OO, but also very pure OO, and I realize, not okay for all. A regular key is considered protected, and one prefixed by an underscore is considered private.
The 'debug' option prints information about what is going on with your hash, its pretty primitive right now. The 'strict_bless' option allows you to replace CORE::GLOBAL::bless by setting it to 'global' (not really recommended), or to supply an list of modules as an array reference and then bless will get replaced just for those modules. The 'allow_auto_vivification_in' option is a little more complex. Normally hash keys must be created before the hash is tied (this is to prevent autovivification from misspellings). However, sometimes I like to separate the creation of my class instances from the actual initialization, as I find it makes classes easier to sub-class. In order to make this work though, I needed to be able to allow autovivification under certain conditions. So any method that matches the reg-ex or string in 'allow_autovivification_in' will be able to autovivifiy. I have other options planned, like making the determination of public/protected/private methods being controlled by reg-exes as well.
This module also catches most cases of name clashes as well. It will detect subclasses stepping on their parent class's private fields, even if the subclass creates it first, and the parent class initializes it later. Of course I am using heuristics for this, since I can't (yet) include code to read minds and/or understand authors intentions ;-P.
Please keep in mind, that this is very much in an alpha stage right now, and not ready for usage, but I wanted to get comments back from people as to; 1) would they use it? and 2) if they would use it what would they like it to be able to do?
-stvn
|
|---|