xref: /openbsd-src/gnu/usr.bin/perl/dist/base/lib/fields.pm (revision 3d61058aa5c692477b6d18acfbbdb653a9930ff9)
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