in reply to Fields pragma - the poor man's OO framework?
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):
Derived.pm:package Base; use strict; use warnings; use fields qw( _f ); sub new { my Base $self = shift; if ( !ref $self ) { $self = fields::new( $self ); } $self->{_f} = 'base'; return $self; } sub base { my Base $self = shift; $self->{_f}; } sub set_base { my Base $self = shift; $self->{_f} = shift; } 1;
Test script:package Derived; use strict; use warnings; use base 'Base'; use fields qw( _f ); sub new { my $class = shift; my Derived $self = fields::new( $class ); $self->SUPER::new(); $self->{_f} = 'derived'; return $self; } sub derived { my Derived $self = shift; $self->{_f}; } 1;
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 4; use Derived; my Derived $obj = Derived->new(); is( $obj->base(), 'base', 'Base::_f eq base' ); is( $obj->derived(), 'derived', 'Derived::_f eq derived' ); diag( 'Setting Base::_f to base2' ); $obj->set_base( 'base2' ); is( $obj->base(), 'base2', 'Base::_f eq base2' ); is( $obj->derived(), 'derived', 'Derived::_f still eq derived' ); 1;
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
(that's the shortest/least ugly syntax that the compiler seems able to compile-time check).sub PKG() { __PACKAGE__ } ... $self->{PKG.'.foo'} = 42;
|
|---|