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

Replies are listed 'Best First'.
Re: RFC - module idea - Devel::StrictObjectHash
by perrin (Chancellor) on Apr 22, 2004 at 17:53 UTC
    Just curious -- are you familiar with the restricted hash feature that was introduced in 5.8.0? It allows you to turn auto-vivification on or off for a given hash.

      No I was not familiar with this. Do you have any links to information on it? It would certainly simplify a good portion of the modules code.

      -stvn
Re: RFC - module idea - Devel::StrictObjectHash
by revdiablo (Prior) on Apr 22, 2004 at 16:41 UTC

    Since there are no replies yet, I thought I'd at least give you some feedback. I think the idea here is neat. The interface looks nice, and the idea seems well thought out. That said, I probably won't use this module, for the same reasons I don't use Tie::SecureHash. Maybe I'm just lazy, and maybe I'm overly confident, but I've never really had a problem with plain, unsafe hash-based objects. If I do, though, hopefully I'll remember your module. It seems like a nice solution.

      revdiablo

      Thanks for your reply. I hear what you are saying, personally I have never really had a problem either with hash-based OO. But then again, I never wrote automated tests either until recently, and after doing so, I was surprised by how much more confident I was in my code. Then after I started using Devel::Cover along with the tests, it was like being able to see my code in a whole new light. Now not only was I confident my code worked (tests), but I knew how much of my code is worked by the tests (code coverage). I hope Devel::StrictObjectHash will go along with tools like these. And just give you that extra added layer of confidence. It funny, cause the idea really is that running the module wont actually do anything, because that means your code is correct :)

      -stvn
        I never wrote automated tests either until recently

        This is another practice that seems like a great idea, but I'm just too lazy to force myself to do it. Some day, I vow, I will write test suites for my code. It's just so hard to do when the code I write is usually used by 1 user: myself... [I know, excuses excuses]

        the idea really is that running the module wont actually do anything, because that means your code is correct

        Indeed, this makes me think of using strict. It's not there for when things go right, it's there for when things go wrong. And of course, since I'm such a big fan of strict, it makes a hypocrite out of me when I say "I've never had a problem with unsafe hashes." I guess I'll just have to live in this state of limbo until I get my act together. 8^)

Re: RFC - module idea - Devel::StrictObjectHash
by stvn (Monsignor) on Apr 22, 2004 at 19:14 UTC

    Speaking of encapsulation, I recently was talking to the researchers who wrote the traits paper, and one of them directed me to this PDF. It is an idea to create flexible encapsulation policies for Smalltalk, which from first glance, may be doable in perl as well. Anyway, maybe after I finish reading it and if its good I will post a mediation on it too.

    -stvn
Re: RFC - module idea - Devel::StrictObjectHash
by Arunbear (Prior) on Apr 23, 2004 at 08:46 UTC

      Yes I have actually. It is interesting, but not what I was looking for. Devel::StrictObjectHash is not really intended to be used directly. It only needs to be loaded and configured, after that it just keeps an eye on plain old hash-based OO code you have already written.

      I wrote this more so that I can continue to code in the same way I have been, but have an extra layer of confidence that assures me that my code is doing what it should. Its along the same philisophical lines as "use strict". In the end you don't want it to do anything, because your code is correct.

      The other reason I wrote this is that all the other solutions I looked into Tie::SecureHash as well as Tie::StrictHash and Devel::Carnivore, were not transparent. All of them required changes to your code to use them, and then changes again to un-use them. Tie has a pretty sizable performace penalty, its not something you want to do lightly. Devel::StrictObjectHash allows you to test your code with almost no alteration (just have to load the module and confiigure it, i can all be in one line), then just as quickly turn it off and not loose your performance.

      -stvn
Re: RFC - module idea - Devel::StrictObjectHash
by ambrus (Abbot) on Apr 24, 2004 at 21:27 UTC

    One solution is to use arrays instead of hashes, it's not as easy to do typos with them. Of course, with arrays you can easily get into an off-by-one error, as in many cases the $kth field of the created object is given by @_[$k+1] in the constructor.

    I know of course that arrays are not quite sufficent in most cases.