waba has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

I'm doing perl OO for $work. Under normal circumstances I'd use a modern framework (Object::InsideOut, Moose, ...), but for various (politic) reasons this isn't possible here. So, I have to stick to whatever can be found in the perl 5.8.8 core modules and use classic blessed hashes for the implementation.

As my hierarchy of classes is expected to grow huge over the time, I'd like to protect their internals from each other. For example, my base class has a 'session' data member which is expected to be private as it is not part of the documented interface. This is all fine and nifty, but there is nothing guaranteeing against a sub-sub-sub-class trying to stuff its own 'session' in the same blessed hash and introducing a subtle bug - and a world of pain.

So far I've guarded against this using a __PACKAGE__ prefix, but I've recently stumbled upon what seems to be a hidden treasure: the fields pragma. It has the following features:

  1. Package-private hash members (_ prefix),
  2. Compile-time (!) check against typoes in the hash access (if declared using my Type $var),
  3. For perl 5.8.x, more efficient access and storage than regular hashes (as it is implemented as a pseudo-hash and the lookup is done at compile time).

Of these, I'm primarily interested by 1, although 2 is pretty nice as well, and 3 is always a bonus. However, is there any known pitfalls with this pragma? I've found this resource about it only, and its main criticism was that fields are "bizarre". Anyone has got some real-world experience with it?

Replies are listed 'Best First'.
Re: Fields pragma - the poor man's OO framework?
by holli (Abbot) on Jul 04, 2008 at 18:34 UTC
    I am curios about the "political" reasons. If it is just because the "unreliable" (sic!) CPAN then grab the code of Object::InsideOut, rename the files, announce it as your own and gain 3 weeks of time to play WoW =)


    holli, /regexed monk/
Re: Fields pragma - the poor man's OO framework?
by perrin (Chancellor) on Jul 04, 2008 at 18:15 UTC
    I'd suggest you read the fields man page from perl 5.10. The pseduo-hashes feature has been removed from perl and the features of this module have changed somewhat.

      I've done so carefully before posting, and as far as I can see the interface (fields::new()) and features are still the same. The only difference is that field access is no longer faster in 5.10, as I stated above.

      So I'm still wondering: if one has to use plain blessed hashes, is there any reason not to get some static checks with fields?


      Anonymous, holli and dragonchild: I'm perfectly aware of the benefits that come with modern OO frameworks, as I use Object::InsideOut in my own projects. However, for various reasons that I don't want to discuss on a public forum, I cannot use them here (openly or otherwise).

        It's fine to use this module, although things like Class::Accessor are generally more popular. However, don't expect any compile-time checking and don't use that "my Type $foo" syntax since that's all pseudo-hashes.
        If you want static checks, don't use fields. Use something like Tie::Hash::FixedKeys.
        use Tie::Hash::FixedKeys; my @keys = qw( a b c ); sub new { my $class = shift; my %args = @_; my $self = {}; tie %$self, 'Tie::Hash::FixedKeys', @keys; foreach my $k ( @keys ) { if ( exists $args{$k} ) { $self->{$k} = $args->{$k}; } } return bless $self, $class; }
        Now, you have all the benefits of static fieldname checking without going into the depths of a deprecated feature. Maybe it's just me, but I'd strongly prefer that.

        Of course, the better solution is to create your own OO framework that auto-generates mutators based on some static list of mutator names. Writing one is the matter of a couple hours. You can even crib heavily from CPAN and call it your own work. That way, everything is a method call. Direct attribute access is horrible practice.


        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Fields pragma - the poor man's OO framework?
by Anonymous Monk on Jul 04, 2008 at 17:28 UTC
    I have to stick to [ ... ] classic blessed hashes for the implementation.
    Even if you cannot use any of the (very useful, highly recommended) modules, can you not use the basic inside-out object/flyweight scalar mechanism coupled with accessor/mutator methods?
Re: Fields pragma - the poor man's OO framework?
by dragonchild (Archbishop) on Jul 05, 2008 at 04:44 UTC
    I have to echo holli here. Just because you cannot install the module from CPAN doesn't mean you cannot grab the module and put it into your project. In a $work project, I had to do exactly that, but because the module wouldn't compile cleanly. So, I grabbed it, fixed it, and it installed with my code.

    Most CPAN authors that I have worked with (and myself, for that matter) aren't really sticklers to "Use my version or else!". As long as you credit the author(s) in a comment somewhere in the code, that's all that's needed. I do that whenever I grab code from Perlmonks. Something along the lines of:

    # Taken from http://www.perlmonks.org/?node_id=5551212 # Thanks to <userid> for providing it! sub foo { # Some useful code here }
    I've done that probably 5-6 times in both CPAN and $work stuff. That not only gives credit where it's due but, as importantly, tells the maintainer (who's the you in 6 months!) where to find the context for the code.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Fields pragma - the poor man's OO framework?
by waba (Monk) on Jul 08, 2008 at 19:16 UTC

    An issue in perl 5.10

    From fields:

    Field names that start with an underscore character are made private to the class and are not visible to subclasses. Inherited fields can be overridden but will generate a warning if used together with the "-w" switch.

    This is however only the case for perl 5.8. Consider the following code (in separate files as base borks if they are in the same script):

    These tests pass on Perl 5.8.8, most likely because of the pseudo-hash implementation. However, on Perl 5.10 _f is shared between Base and Derived, and base() always returns the same as derived().

    What's more, the documented warning is emitted only for public fields, so Perl stays silent here, while it would croak had I named my field f. This sounds like a bug, I'll try to report it when I have some free time.

    In the end, I think that fields are still usable, but unless (until?) this issue gets resolved, private fields are best implemented as

    sub PKG() { __PACKAGE__ } ... $self->{PKG.'.foo'} = 42;
    (that's the shortest/least ugly syntax that the compiler seems able to compile-time check).