1b8851fccSafresh1use 5.008; 2b39c5158Smillertpackage fields; 3b39c5158Smillert 4b39c5158Smillertrequire 5.005; 5b39c5158Smillertuse strict; 6b39c5158Smillertno strict 'refs'; 7b39c5158Smillertunless( eval q{require warnings::register; warnings::register->import; 1} ) { 8b39c5158Smillert *warnings::warnif = sub { 9b39c5158Smillert require Carp; 10b39c5158Smillert Carp::carp(@_); 11b39c5158Smillert } 12b39c5158Smillert} 139f11ffb7Safresh1our %attr; 14b39c5158Smillert 15*3d61058aSafresh1our $VERSION = '2.25'; 16b8851fccSafresh1$VERSION =~ tr/_//d; 17b39c5158Smillert 18b39c5158Smillert# constant.pm is slow 19b39c5158Smillertsub PUBLIC () { 2**0 } 20b39c5158Smillertsub PRIVATE () { 2**1 } 21b39c5158Smillertsub INHERITED () { 2**2 } 22b39c5158Smillertsub PROTECTED () { 2**3 } 23b39c5158Smillert 24b39c5158Smillert 25b39c5158Smillert# The %attr hash holds the attributes of the currently assigned fields 26b39c5158Smillert# per class. The hash is indexed by class names and the hash value is 27b39c5158Smillert# an array reference. The first element in the array is the lowest field 28b39c5158Smillert# number not belonging to a base class. The remaining elements' indices 29b39c5158Smillert# are the field numbers. The values are integer bit masks, or undef 30b39c5158Smillert# in the case of base class private fields (which occupy a slot but are 31b39c5158Smillert# otherwise irrelevant to the class). 32b39c5158Smillert 33b39c5158Smillertsub import { 34b39c5158Smillert my $class = shift; 35b39c5158Smillert return unless @_; 36b39c5158Smillert my $package = caller(0); 37b39c5158Smillert # avoid possible typo warnings 38b39c5158Smillert %{"$package\::FIELDS"} = () unless %{"$package\::FIELDS"}; 39b39c5158Smillert my $fields = \%{"$package\::FIELDS"}; 40b39c5158Smillert my $fattr = ($attr{$package} ||= [1]); 41b39c5158Smillert my $next = @$fattr; 42b39c5158Smillert 43b39c5158Smillert # Quiet pseudo-hash deprecation warning for uses of fields::new. 44b39c5158Smillert bless \%{"$package\::FIELDS"}, 'pseudohash'; 45b39c5158Smillert 46b39c5158Smillert if ($next > $fattr->[0] 47b39c5158Smillert and ($fields->{$_[0]} || 0) >= $fattr->[0]) 48b39c5158Smillert { 49b39c5158Smillert # There are already fields not belonging to base classes. 50b39c5158Smillert # Looks like a possible module reload... 51b39c5158Smillert $next = $fattr->[0]; 52b39c5158Smillert } 53b39c5158Smillert foreach my $f (@_) { 54b39c5158Smillert my $fno = $fields->{$f}; 55b39c5158Smillert 56b39c5158Smillert # Allow the module to be reloaded so long as field positions 57b39c5158Smillert # have not changed. 58b39c5158Smillert if ($fno and $fno != $next) { 59b39c5158Smillert require Carp; 60b39c5158Smillert if ($fno < $fattr->[0]) { 61b39c5158Smillert if ($] < 5.006001) { 62b39c5158Smillert warn("Hides field '$f' in base class") if $^W; 63b39c5158Smillert } else { 64b39c5158Smillert warnings::warnif("Hides field '$f' in base class") ; 65b39c5158Smillert } 66b39c5158Smillert } else { 67b39c5158Smillert Carp::croak("Field name '$f' already in use"); 68b39c5158Smillert } 69b39c5158Smillert } 70b39c5158Smillert $fields->{$f} = $next; 71b39c5158Smillert $fattr->[$next] = ($f =~ /^_/) ? PRIVATE : PUBLIC; 72b39c5158Smillert $next += 1; 73b39c5158Smillert } 74b39c5158Smillert if (@$fattr > $next) { 75b39c5158Smillert # Well, we gave them the benefit of the doubt by guessing the 76b39c5158Smillert # module was reloaded, but they appear to be declaring fields 77b39c5158Smillert # in more than one place. We can't be sure (without some extra 78b39c5158Smillert # bookkeeping) that the rest of the fields will be declared or 79b39c5158Smillert # have the same positions, so punt. 80b39c5158Smillert require Carp; 81b39c5158Smillert Carp::croak ("Reloaded module must declare all fields at once"); 82b39c5158Smillert } 83b39c5158Smillert} 84b39c5158Smillert 85b39c5158Smillertsub inherit { 86b39c5158Smillert require base; 87b39c5158Smillert goto &base::inherit_fields; 88b39c5158Smillert} 89b39c5158Smillert 90b39c5158Smillertsub _dump # sometimes useful for debugging 91b39c5158Smillert{ 92b39c5158Smillert for my $pkg (sort keys %attr) { 93b39c5158Smillert print "\n$pkg"; 94b39c5158Smillert if (@{"$pkg\::ISA"}) { 95b39c5158Smillert print " (", join(", ", @{"$pkg\::ISA"}), ")"; 96b39c5158Smillert } 97b39c5158Smillert print "\n"; 98b39c5158Smillert my $fields = \%{"$pkg\::FIELDS"}; 99b39c5158Smillert for my $f (sort {$fields->{$a} <=> $fields->{$b}} keys %$fields) { 100b39c5158Smillert my $no = $fields->{$f}; 101b39c5158Smillert print " $no: $f"; 102b39c5158Smillert my $fattr = $attr{$pkg}[$no]; 103b39c5158Smillert if (defined $fattr) { 104b39c5158Smillert my @a; 105b39c5158Smillert push(@a, "public") if $fattr & PUBLIC; 106b39c5158Smillert push(@a, "private") if $fattr & PRIVATE; 107b39c5158Smillert push(@a, "inherited") if $fattr & INHERITED; 108b39c5158Smillert print "\t(", join(", ", @a), ")"; 109b39c5158Smillert } 110b39c5158Smillert print "\n"; 111b39c5158Smillert } 112b39c5158Smillert } 113b39c5158Smillert} 114b39c5158Smillert 115b39c5158Smillertif ($] < 5.009) { 116b39c5158Smillert *new = sub { 117b39c5158Smillert my $class = shift; 118b39c5158Smillert $class = ref $class if ref $class; 119b39c5158Smillert return bless [\%{$class . "::FIELDS"}], $class; 120b39c5158Smillert } 121b39c5158Smillert} else { 122b39c5158Smillert *new = sub { 123b39c5158Smillert my $class = shift; 124b39c5158Smillert $class = ref $class if ref $class; 125b39c5158Smillert require Hash::Util; 126b39c5158Smillert my $self = bless {}, $class; 127b39c5158Smillert 128b39c5158Smillert # The lock_keys() prototype won't work since we require Hash::Util :( 129b39c5158Smillert &Hash::Util::lock_keys(\%$self, _accessible_keys($class)); 130b39c5158Smillert return $self; 131b39c5158Smillert } 132b39c5158Smillert} 133b39c5158Smillert 134b39c5158Smillertsub _accessible_keys { 135b39c5158Smillert my ($class) = @_; 136b39c5158Smillert return ( 137b39c5158Smillert keys %{$class.'::FIELDS'}, 138b39c5158Smillert map(_accessible_keys($_), @{$class.'::ISA'}), 139b39c5158Smillert ); 140b39c5158Smillert} 141b39c5158Smillert 142b39c5158Smillertsub phash { 143b39c5158Smillert die "Pseudo-hashes have been removed from Perl" if $] >= 5.009; 144b39c5158Smillert my $h; 145b39c5158Smillert my $v; 146b39c5158Smillert if (@_) { 147b39c5158Smillert if (ref $_[0] eq 'ARRAY') { 148b39c5158Smillert my $a = shift; 149b39c5158Smillert @$h{@$a} = 1 .. @$a; 150b39c5158Smillert if (@_) { 151b39c5158Smillert $v = shift; 152b39c5158Smillert unless (! @_ and ref $v eq 'ARRAY') { 153b39c5158Smillert require Carp; 154b39c5158Smillert Carp::croak ("Expected at most two array refs\n"); 155b39c5158Smillert } 156b39c5158Smillert } 157b39c5158Smillert } 158b39c5158Smillert else { 159b39c5158Smillert if (@_ % 2) { 160b39c5158Smillert require Carp; 161b39c5158Smillert Carp::croak ("Odd number of elements initializing pseudo-hash\n"); 162b39c5158Smillert } 163b39c5158Smillert my $i = 0; 164b39c5158Smillert @$h{grep ++$i % 2, @_} = 1 .. @_ / 2; 165b39c5158Smillert $i = 0; 166b39c5158Smillert $v = [grep $i++ % 2, @_]; 167b39c5158Smillert } 168b39c5158Smillert } 169b39c5158Smillert else { 170b39c5158Smillert $h = {}; 171b39c5158Smillert $v = []; 172b39c5158Smillert } 173b39c5158Smillert [ $h, @$v ]; 174b39c5158Smillert 175b39c5158Smillert} 176b39c5158Smillert 177b39c5158Smillert1; 178b39c5158Smillert 179b39c5158Smillert__END__ 180b39c5158Smillert 181b39c5158Smillert=head1 NAME 182b39c5158Smillert 183b39c5158Smillertfields - compile-time class fields 184b39c5158Smillert 185b39c5158Smillert=head1 SYNOPSIS 186b39c5158Smillert 187b39c5158Smillert { 188b39c5158Smillert package Foo; 189b39c5158Smillert use fields qw(foo bar _Foo_private); 190b39c5158Smillert sub new { 191b39c5158Smillert my Foo $self = shift; 192b39c5158Smillert unless (ref $self) { 193b39c5158Smillert $self = fields::new($self); 194b39c5158Smillert $self->{_Foo_private} = "this is Foo's secret"; 195b39c5158Smillert } 196b39c5158Smillert $self->{foo} = 10; 197b39c5158Smillert $self->{bar} = 20; 198b39c5158Smillert return $self; 199b39c5158Smillert } 200b39c5158Smillert } 201b39c5158Smillert 202b39c5158Smillert my $var = Foo->new; 203b39c5158Smillert $var->{foo} = 42; 204b39c5158Smillert 2056fb12b70Safresh1 # this will generate a run-time error 206b39c5158Smillert $var->{zap} = 42; 207b39c5158Smillert 2086fb12b70Safresh1 # this will generate a compile-time error 2096fb12b70Safresh1 my Foo $foo = Foo->new; 2106fb12b70Safresh1 $foo->{zap} = 24; 2116fb12b70Safresh1 212b39c5158Smillert # subclassing 213b39c5158Smillert { 214b39c5158Smillert package Bar; 215b39c5158Smillert use base 'Foo'; 216b39c5158Smillert use fields qw(baz _Bar_private); # not shared with Foo 217b39c5158Smillert sub new { 218b39c5158Smillert my $class = shift; 219b39c5158Smillert my $self = fields::new($class); 220b39c5158Smillert $self->SUPER::new(); # init base fields 221b39c5158Smillert $self->{baz} = 10; # init own fields 222b39c5158Smillert $self->{_Bar_private} = "this is Bar's secret"; 223b39c5158Smillert return $self; 224b39c5158Smillert } 225b39c5158Smillert } 226b39c5158Smillert 227b39c5158Smillert=head1 DESCRIPTION 228b39c5158Smillert 2296fb12b70Safresh1The C<fields> pragma enables compile-time and run-time verified class 2306fb12b70Safresh1fields. 231b39c5158Smillert 232b39c5158SmillertNOTE: The current implementation keeps the declared fields in the %FIELDS 233b39c5158Smillerthash of the calling package, but this may change in future versions. 234b39c5158SmillertDo B<not> update the %FIELDS hash directly, because it must be created 235b39c5158Smillertat compile-time for it to be fully useful, as is done by this pragma. 236b39c5158Smillert 2376fb12b70Safresh1If a typed lexical variable (C<my Class 2386fb12b70Safresh1$var>) holding a reference is used to access a 239b39c5158Smillerthash element and a package with the same name as the type has 2406fb12b70Safresh1declared class fields using this pragma, then the hash key is 2416fb12b70Safresh1verified at compile time. If the variables are not typed, access is 2426fb12b70Safresh1only checked at run time. 243b39c5158Smillert 244b39c5158SmillertThe related C<base> pragma will combine fields from base classes and any 245b39c5158Smillertfields declared using the C<fields> pragma. This enables field 2466fb12b70Safresh1inheritance to work properly. Inherited fields can be overridden but 2476fb12b70Safresh1will generate a warning if warnings are enabled. 248b39c5158Smillert 2496fb12b70Safresh1B<Only valid for Perl 5.8.x and earlier:> Field names that start with an 2506fb12b70Safresh1underscore character are made private to the class and are not visible 2516fb12b70Safresh1to subclasses. 252b39c5158Smillert 2536fb12b70Safresh1Also, B<in Perl 5.8.x and earlier>, this pragma uses pseudo-hashes, the 2546fb12b70Safresh1effect being that you can have objects with named fields which are as 2556fb12b70Safresh1compact and as fast arrays to access, as long as the objects are 2566fb12b70Safresh1accessed through properly typed variables. 257b39c5158Smillert 258b39c5158SmillertThe following functions are supported: 259b39c5158Smillert 260b39c5158Smillert=over 4 261b39c5158Smillert 262b39c5158Smillert=item new 263b39c5158Smillert 264*3d61058aSafresh1fields::new() creates and blesses a hash of the fields declared 2656fb12b70Safresh1using the C<fields> pragma into the specified class. It is the 266b39c5158Smillertrecommended way to construct a fields-based object. 267b39c5158Smillert 268b39c5158SmillertThis makes it possible to write a constructor like this: 269b39c5158Smillert 270b39c5158Smillert package Critter::Sounds; 271b39c5158Smillert use fields qw(cat dog bird); 272b39c5158Smillert 273b39c5158Smillert sub new { 274b39c5158Smillert my $self = shift; 275b39c5158Smillert $self = fields::new($self) unless ref $self; 276b39c5158Smillert $self->{cat} = 'meow'; # scalar element 277b39c5158Smillert @$self{'dog','bird'} = ('bark','tweet'); # slice 278b39c5158Smillert return $self; 279b39c5158Smillert } 280b39c5158Smillert 281b39c5158Smillert=item phash 282b39c5158Smillert 2836fb12b70Safresh1B<This function only works in Perl 5.8.x and earlier.> Pseudo-hashes 2846fb12b70Safresh1were removed from Perl as of 5.10. Consider using restricted hashes or 2856fb12b70Safresh1fields::new() instead (which itself uses restricted hashes under 5.10+). 2866fb12b70Safresh1See L<Hash::Util>. Using fields::phash() under 5.10 or higher will 2876fb12b70Safresh1cause an error. 288b39c5158Smillert 289b39c5158Smillertfields::phash() can be used to create and initialize a plain (unblessed) 290b39c5158Smillertpseudo-hash. This function should always be used instead of creating 291b39c5158Smillertpseudo-hashes directly. 292b39c5158Smillert 293b39c5158SmillertIf the first argument is a reference to an array, the pseudo-hash will 294b39c5158Smillertbe created with keys from that array. If a second argument is supplied, 295b39c5158Smillertit must also be a reference to an array whose elements will be used as 296b39c5158Smillertthe values. If the second array contains less elements than the first, 297b39c5158Smillertthe trailing elements of the pseudo-hash will not be initialized. 298b39c5158SmillertThis makes it particularly useful for creating a pseudo-hash from 299b39c5158Smillertsubroutine arguments: 300b39c5158Smillert 301b39c5158Smillert sub dogtag { 302b39c5158Smillert my $tag = fields::phash([qw(name rank ser_num)], [@_]); 303b39c5158Smillert } 304b39c5158Smillert 305b39c5158Smillertfields::phash() also accepts a list of key-value pairs that will 306b39c5158Smillertbe used to construct the pseudo hash. Examples: 307b39c5158Smillert 308b39c5158Smillert my $tag = fields::phash(name => "Joe", 309b39c5158Smillert rank => "captain", 310b39c5158Smillert ser_num => 42); 311b39c5158Smillert 312b39c5158Smillert my $pseudohash = fields::phash(%args); 313b39c5158Smillert 314b39c5158Smillert=back 315b39c5158Smillert 316b39c5158Smillert=head1 SEE ALSO 317b39c5158Smillert 3186fb12b70Safresh1L<base>, L<Hash::Util> 319b39c5158Smillert 320b39c5158Smillert=cut 321