http://qs321.pair.com?node_id=247181

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

I'm using the fields and base pragmata in 5.8.0 for some OO stuff I'm working on. I find the combination pretty elegant, and appreciate them very much.

However, I've encountered a small problem (that vexed me quite a bit until I figured out where the issue was). Specifically, if all of the fields in a super-class are private (i.e., their names start with underscores), then sub-classes fail to respect them when inheriting. The result is that new fields in the sub-class write themselves into the same pseudo-hash slots as the fields of the super class. If there is even one non-private field in the super-class, then the sub-class fields make room for all of the super-class fields (even the private ones).

To be more specific, if the superclass Foo starts like this:

package Foo; use strict; use fields qw(_foo); ...
and a subclass Bar looks like this:
package Bar; use strict; use base 'Foo'; use fields qw(_bar _baz); ...
Then if you set the _bar field for a Bar instance, it clobbers whatever was in the _foo field. But if Foo was defined as this instead:
package Foo; use strict; use fields qw(unused _foo); ...
Then Bar respects Foo's fields (even the private ones).

I've put up a page with a script demonstrating the problem, and another script with the trivial fix. Output of each script is at the bottom, after __END__. You can also see the output of perl -V.

Is this a known problem? Is there a patch already available? If not, to whose attention should I bring it? It's not a big deal to work around ("unused" field, anyone?), but it seems to me that base.pm and fields.pm probably be fixed.

Replies are listed 'Best First'.
Re: Bug in 5.8.0 fields/base pragmata?
by Thelonius (Priest) on Apr 01, 2003 at 15:26 UTC
    I tried your test program with perl 5.8.0 on two different platforms (neither Linux). Both worked fine--I could not reproduce the bug. Make sure that you don't have an old version of 'fields.pm' in your @INC path. When I do this:
    perl -Mfields -le 'print $fields::VERSION'
    I get 1.02.

    You can search for known bugs at bugs.perl.org. You can report one using the "perlbug" program that comes with perl.

      Aha! I have a newer version of fields.pm.

      Mine says 1.0201, which is probably because I installed Class::Fields, which appears to overwrite base.pm and fields.pm.

      So perhaps this bug is really in the Class::Fields module. I'll contact its author about it and report back.

Re: Bug in 5.8.0 fields/base pragmata?
by pg (Canon) on Apr 01, 2003 at 16:00 UTC
    In general, starting from Perl 5.8, fields should no longer be used, and expect it to be threw away in coming versions, or at least totally unrecognizable.

    Now, for this functionality, you should use Hash::Util instead.

    You can read this post of mine for details.

      According to perlref for 5.8.0, the fields pragma will remain available in future versions. It's not going away -- p5p doesn't break backwards compatability that lightly. (Underneath, it may actually use locked hash keys!)

        You missed the main point. I would agree with you, if
        1. "use fields" is just a single use statement
        2. its user interface is stable and independent from its underlying implementation
        Unfortunately, this is not the case.

        If those were true statement, then you would be right, as the compatibility (when one uses the word "compatibility", always ask the question "what is the level of compatibility?") is fully granted.

        However, "use fields" comes with a really clumsy interface, which is tightly coupled with its underlying pseudo hash, which has attracted lots of strong criticism, since its birth.

        Logically, whether "use fields" would be there in the future is irrelevent here.

        Especially if what you guessed is true that the underlying implementation would change to use lock_keys, then it makes even less sense using fields in NEW development, instead of using lock_keys directly.

Re: Bug in 5.8.0 fields/base pragmata?
by schwern (Scribe) on Apr 05, 2003 at 03:22 UTC

    Confirmed, this is a bug in Class::Field's implementation of fields.pm. 5.8.0's version does it right. I'll look into it, but don't expect anything soon as I've got my hands full working on stuff for 5.8.1.

    I will most definately agree that fields.pm is a clumsy interface and would discourage its use in new code. Consider using something a bit more sophisticated. Class::Accessor, Class::Struct, Class::Class, Class::Generate... or whatever the state of the art for class generation and privacy is these days. I could also recommend a few simple tricks.

    As for it being deprecated, or going to be thrown away, or in risk of having backwards compatibility problems in future versions of Perl, this is not true. Pseudo-hashes are going away, fields.pm is not. It will continue to work using restricted hashes. As long as you're using fields::new() and treating the resulting object exclusively as a hash you are safe.

    Certain bits of fields.pm *are* going away. Anything that obviously exposes the underlying psuedo-hash is gone. That means fields::phash() and any time you assume your object is an array ref. %FIELDS will still be around, but don't trust that either.

    On the flip side, using Hash::Util and lock_keys() directly means your code is tied to 5.8.0 and up. If you use fields.pm you can at least be backwards compatible. Hash::Util was not intended to be used directly in programs, it was thrown into 5.8.0 to have *some* user interface to restricted hashes upon which someone could write another more user friendly module around.

    If you want to see how this all plays out, try a copy of bleadperl. All of the above has already happened. The current version of Class::Fields also already takes restricted hashes into account.

    You can consider this semi-authoritative. I wrote Class::Fields, fixed and then killed pseudo-hashes, ported fields.pm to use restricted hashes in 5.9 and wrote Hash::Util. I have some experience with the subject. ;)

      Here is a test case that reliably demonstrates the problem on 5.8.0. If you move the second "use base" to before the preceeding "use fields" the test will succeed. Internally %Bar::FIELDS is getting populated with duplicate values which is causing the trouble.
      package Foo; use strict; use fields qw(Foo_field); sub new ($) { return fields::new(shift); } package Bar; use strict; use fields qw(Bar_field); use base qw(Foo); package main; use Test::More 'no_plan'; my Bar $obj = new Bar(); ok ($obj, "got instance"); ok ($obj->isa("Bar"), "it's a Bar"); ok ($obj->isa("Foo"), "it's a Foo"); ok ($obj->{Bar_field} = 2, "Can assign Bar_field"); ok ($obj->{Foo_field} = 3, "Can assign Foo_field"); is ($obj->{Bar_field}, 2, "Bar is assigned"); is ($obj->{Foo_field}, 3, "Foo is assigned");