This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
undo change#5506; add patch to make blank line warnings optional
[perl5.git] / lib / fields.pm
CommitLineData
458fb581
MB
1package fields;
2
d516a115
JH
3=head1 NAME
4
5fields - compile-time class fields
6
7=head1 SYNOPSIS
8
9 {
10 package Foo;
479ba383
GS
11 use fields qw(foo bar _Foo_private);
12 sub new {
13 my Foo $self = shift;
14 unless (ref $self) {
15 $self = fields::new($self);
16 $self->{_Foo_private} = "this is Foo's secret";
17 }
18 $self->{foo} = 10;
19 $self->{bar} = 20;
20 return $self;
21 }
d516a115 22 }
479ba383
GS
23
24 my Foo $var = Foo::->new;
d516a115
JH
25 $var->{foo} = 42;
26
479ba383 27 # this will generate a compile-time error
d516a115
JH
28 $var->{zap} = 42;
29
479ba383 30 # subclassing
f1192cee
GA
31 {
32 package Bar;
33 use base 'Foo';
479ba383
GS
34 use fields qw(baz _Bar_private); # not shared with Foo
35 sub new {
36 my $class = shift;
37 my $self = fields::new($class);
38 $self->SUPER::new(); # init base fields
39 $self->{baz} = 10; # init own fields
40 $self->{_Bar_private} = "this is Bar's secret";
41 return $self;
42 }
f1192cee
GA
43 }
44
d516a115
JH
45=head1 DESCRIPTION
46
479ba383
GS
47The C<fields> pragma enables compile-time verified class fields.
48
49NOTE: The current implementation keeps the declared fields in the %FIELDS
50hash of the calling package, but this may change in future versions.
51Do B<not> update the %FIELDS hash directly, because it must be created
52at compile-time for it to be fully useful, as is done by this pragma.
f1192cee
GA
53
54If a typed lexical variable holding a reference is used to access a
479ba383
GS
55hash element and a package with the same name as the type has declared
56class fields using this pragma, then the operation is turned into an
57array access at compile time.
58
59The related C<base> pragma will combine fields from base classes and any
33e06c89 60fields declared using the C<fields> pragma. This enables field
479ba383
GS
61inheritance to work properly.
62
63Field names that start with an underscore character are made private to
64the class and are not visible to subclasses. Inherited fields can be
51301382
GS
65overridden but will generate a warning if used together with the C<-w>
66switch.
f1192cee
GA
67
68The effect of all this is that you can have objects with named fields
51301382 69which are as compact and as fast arrays to access. This only works
f1192cee 70as long as the objects are accessed through properly typed variables.
479ba383
GS
71If the objects are not typed, access is only checked at run time.
72
73The following functions are supported:
74
75=over 8
76
77=item new
f1192cee 78
479ba383
GS
79fields::new() creates and blesses a pseudo-hash comprised of the fields
80declared using the C<fields> pragma into the specified class.
81This makes it possible to write a constructor like this:
82
83 package Critter::Sounds;
84 use fields qw(cat dog bird);
85
86 sub new {
87 my Critter::Sounds $self = shift;
33e06c89 88 $self = fields::new($self) unless ref $self;
479ba383 89 $self->{cat} = 'meow'; # scalar element
33e06c89 90 @$self{'dog','bird'} = ('bark','tweet'); # slice
479ba383
GS
91 return $self;
92 }
93
94=item phash
95
96fields::phash() can be used to create and initialize a plain (unblessed)
97pseudo-hash. This function should always be used instead of creating
98pseudo-hashes directly.
99
100If the first argument is a reference to an array, the pseudo-hash will
101be created with keys from that array. If a second argument is supplied,
102it must also be a reference to an array whose elements will be used as
103the values. If the second array contains less elements than the first,
104the trailing elements of the pseudo-hash will not be initialized.
105This makes it particularly useful for creating a pseudo-hash from
106subroutine arguments:
107
108 sub dogtag {
109 my $tag = fields::phash([qw(name rank ser_num)], [@_]);
110 }
f1192cee 111
479ba383
GS
112fields::phash() also accepts a list of key-value pairs that will
113be used to construct the pseudo hash. Examples:
114
115 my $tag = fields::phash(name => "Joe",
116 rank => "captain",
117 ser_num => 42);
118
119 my $pseudohash = fields::phash(%args);
120
121=back
f1192cee
GA
122
123=head1 SEE ALSO
124
125L<base>,
31a572f1 126L<perlref/Pseudo-hashes: Using an array as a hash>
d516a115
JH
127
128=cut
129
17f410f9 130use 5.005_64;
f1192cee
GA
131use strict;
132no strict 'refs';
17f410f9 133our(%attr, $VERSION);
f1192cee 134
f30a1143 135$VERSION = "1.01";
f1192cee
GA
136
137# some constants
138sub _PUBLIC () { 1 }
139sub _PRIVATE () { 2 }
f1192cee
GA
140
141# The %attr hash holds the attributes of the currently assigned fields
142# per class. The hash is indexed by class names and the hash value is
f30a1143
JT
143# an array reference. The first element in the array is the lowest field
144# number not belonging to a base class. The remaining elements' indices
145# are the field numbers. The values are integer bit masks, or undef
146# in the case of base class private fields (which occupy a slot but are
147# otherwise irrelevant to the class).
f1192cee 148
458fb581
MB
149sub import {
150 my $class = shift;
f30a1143 151 return unless @_;
f1192cee 152 my $package = caller(0);
479ba383
GS
153 # avoid possible typo warnings
154 %{"$package\::FIELDS"} = () unless %{"$package\::FIELDS"};
458fb581 155 my $fields = \%{"$package\::FIELDS"};
f30a1143
JT
156 my $fattr = ($attr{$package} ||= [1]);
157 my $next = @$fattr;
f1192cee 158
f30a1143
JT
159 if ($next > $fattr->[0]
160 and ($fields->{$_[0]} || 0) >= $fattr->[0])
161 {
162 # There are already fields not belonging to base classes.
163 # Looks like a possible module reload...
164 $next = $fattr->[0];
165 }
458fb581 166 foreach my $f (@_) {
f30a1143
JT
167 my $fno = $fields->{$f};
168
169 # Allow the module to be reloaded so long as field positions
170 # have not changed.
171 if ($fno and $fno != $next) {
458fb581 172 require Carp;
f30a1143 173 if ($fno < $fattr->[0]) {
f1192cee
GA
174 Carp::carp("Hides field '$f' in base class") if $^W;
175 } else {
176 Carp::croak("Field name '$f' already in use");
177 }
458fb581 178 }
f30a1143
JT
179 $fields->{$f} = $next;
180 $fattr->[$next] = ($f =~ /^_/) ? _PRIVATE : _PUBLIC;
181 $next += 1;
182 }
183 if (@$fattr > $next) {
184 # Well, we gave them the benefit of the doubt by guessing the
185 # module was reloaded, but they appear to be declaring fields
186 # in more than one place. We can't be sure (without some extra
187 # bookkeeping) that the rest of the fields will be declared or
188 # have the same positions, so punt.
189 require Carp;
190 Carp::croak ("Reloaded module must declare all fields at once");
458fb581 191 }
f1192cee
GA
192}
193
479ba383 194sub inherit { # called by base.pm when $base_fields is nonempty
f1192cee 195 my($derived, $base) = @_;
f30a1143
JT
196 my $base_attr = $attr{$base};
197 my $derived_attr = $attr{$derived} ||= [];
479ba383
GS
198 # avoid possible typo warnings
199 %{"$base\::FIELDS"} = () unless %{"$base\::FIELDS"};
200 %{"$derived\::FIELDS"} = () unless %{"$derived\::FIELDS"};
f30a1143
JT
201 my $base_fields = \%{"$base\::FIELDS"};
202 my $derived_fields = \%{"$derived\::FIELDS"};
203
204 $derived_attr->[0] = $base_attr ? scalar(@$base_attr) : 1;
205 while (my($k,$v) = each %$base_fields) {
206 my($fno);
207 if ($fno = $derived_fields->{$k} and $fno != $v) {
208 require Carp;
209 Carp::croak ("Inherited %FIELDS can't override existing %FIELDS");
210 }
211 if ($base_attr->[$v] & _PRIVATE) {
212 $derived_attr->[$v] = undef;
213 } else {
214 $derived_attr->[$v] = $base_attr->[$v];
215 $derived_fields->{$k} = $v;
216 }
217 }
f1192cee
GA
218}
219
220sub _dump # sometimes useful for debugging
221{
479ba383
GS
222 for my $pkg (sort keys %attr) {
223 print "\n$pkg";
224 if (@{"$pkg\::ISA"}) {
225 print " (", join(", ", @{"$pkg\::ISA"}), ")";
226 }
227 print "\n";
228 my $fields = \%{"$pkg\::FIELDS"};
229 for my $f (sort {$fields->{$a} <=> $fields->{$b}} keys %$fields) {
230 my $no = $fields->{$f};
231 print " $no: $f";
232 my $fattr = $attr{$pkg}[$no];
233 if (defined $fattr) {
234 my @a;
235 push(@a, "public") if $fattr & _PUBLIC;
236 push(@a, "private") if $fattr & _PRIVATE;
237 push(@a, "inherited") if $no < $attr{$pkg}[0];
238 print "\t(", join(", ", @a), ")";
239 }
240 print "\n";
241 }
242 }
243}
244
245sub new {
246 my $class = shift;
247 $class = ref $class if ref $class;
248 return bless [\%{$class . "::FIELDS"}], $class;
249}
250
251sub phash {
252 my $h;
253 my $v;
254 if (@_) {
255 if (ref $_[0] eq 'ARRAY') {
256 my $a = shift;
257 @$h{@$a} = 1 .. @$a;
258 if (@_) {
259 $v = shift;
260 unless (! @_ and ref $v eq 'ARRAY') {
261 require Carp;
262 Carp::croak ("Expected at most two array refs\n");
263 }
264 }
265 }
266 else {
267 if (@_ % 2) {
268 require Carp;
269 Carp::croak ("Odd number of elements initializing pseudo-hash\n");
270 }
271 my $i = 0;
272 @$h{grep ++$i % 2, @_} = 1 .. @_ / 2;
273 $i = 0;
274 $v = [grep $i++ % 2, @_];
275 }
276 }
277 else {
278 $h = {};
279 $v = [];
280 }
281 [ $h, @$v ];
458fb581
MB
282}
283
2841;