fix diagnostics to report "our" vs "my" correctly
[p5sagit/p5-mst-13.2.git] / lib / fields.pm
CommitLineData
458fb581 1package fields;
2
d516a115 3=head1 NAME
4
5fields - compile-time class fields
6
7=head1 SYNOPSIS
8
9 {
10 package Foo;
f1192cee 11 use fields qw(foo bar _private);
d516a115 12 }
13 ...
14 my Foo $var = new Foo;
15 $var->{foo} = 42;
16
17 # This will generate a compile-time error.
18 $var->{zap} = 42;
19
f1192cee 20 {
21 package Bar;
22 use base 'Foo';
23 use fields 'bar'; # hides Foo->{bar}
24 use fields qw(baz _private); # not shared with Foo
25 }
26
d516a115 27=head1 DESCRIPTION
28
f1192cee 29The C<fields> pragma enables compile-time verified class fields. It
30does so by updating the %FIELDS hash in the calling package.
31
32If a typed lexical variable holding a reference is used to access a
33hash element and the %FIELDS hash of the given type exists, then the
34operation is turned into an array access at compile time. The %FIELDS
c5c7a622 35hash maps from hash element names to the array indices. If the hash
f1192cee 36element is not present in the %FIELDS hash, then a compile-time error
37is signaled.
38
39Since the %FIELDS hash is used at compile-time, it must be set up at
40compile-time too. This is made easier with the help of the 'fields'
41and the 'base' pragma modules. The 'base' pragma will copy fields
42from base classes and the 'fields' pragma adds new fields. Field
43names that start with an underscore character are made private to a
44class and are not visible to subclasses. Inherited fields can be
51301382 45overridden but will generate a warning if used together with the C<-w>
46switch.
f1192cee 47
48The effect of all this is that you can have objects with named fields
51301382 49which are as compact and as fast arrays to access. This only works
f1192cee 50as long as the objects are accessed through properly typed variables.
51For untyped access to work you have to make sure that a reference to
52the proper %FIELDS hash is assigned to the 0'th element of the array
31a572f1 53object (so that the objects can be treated like an pseudo-hash). A
f1192cee 54constructor like this does the job:
55
56 sub new
57 {
58 my $class = shift;
59 no strict 'refs';
c5c7a622 60 my $self = bless [\%{"$class\::FIELDS"}], $class;
f1192cee 61 $self;
62 }
63
64
65=head1 SEE ALSO
66
67L<base>,
31a572f1 68L<perlref/Pseudo-hashes: Using an array as a hash>
d516a115 69
70=cut
71
f1192cee 72use strict;
73no strict 'refs';
74use vars qw(%attr $VERSION);
75
f30a1143 76$VERSION = "1.01";
f1192cee 77
78# some constants
79sub _PUBLIC () { 1 }
80sub _PRIVATE () { 2 }
f1192cee 81
82# The %attr hash holds the attributes of the currently assigned fields
83# per class. The hash is indexed by class names and the hash value is
f30a1143 84# an array reference. The first element in the array is the lowest field
85# number not belonging to a base class. The remaining elements' indices
86# are the field numbers. The values are integer bit masks, or undef
87# in the case of base class private fields (which occupy a slot but are
88# otherwise irrelevant to the class).
f1192cee 89
458fb581 90sub import {
91 my $class = shift;
f30a1143 92 return unless @_;
f1192cee 93 my $package = caller(0);
458fb581 94 my $fields = \%{"$package\::FIELDS"};
f30a1143 95 my $fattr = ($attr{$package} ||= [1]);
96 my $next = @$fattr;
f1192cee 97
f30a1143 98 if ($next > $fattr->[0]
99 and ($fields->{$_[0]} || 0) >= $fattr->[0])
100 {
101 # There are already fields not belonging to base classes.
102 # Looks like a possible module reload...
103 $next = $fattr->[0];
104 }
458fb581 105 foreach my $f (@_) {
f30a1143 106 my $fno = $fields->{$f};
107
108 # Allow the module to be reloaded so long as field positions
109 # have not changed.
110 if ($fno and $fno != $next) {
458fb581 111 require Carp;
f30a1143 112 if ($fno < $fattr->[0]) {
f1192cee 113 Carp::carp("Hides field '$f' in base class") if $^W;
114 } else {
115 Carp::croak("Field name '$f' already in use");
116 }
458fb581 117 }
f30a1143 118 $fields->{$f} = $next;
119 $fattr->[$next] = ($f =~ /^_/) ? _PRIVATE : _PUBLIC;
120 $next += 1;
121 }
122 if (@$fattr > $next) {
123 # Well, we gave them the benefit of the doubt by guessing the
124 # module was reloaded, but they appear to be declaring fields
125 # in more than one place. We can't be sure (without some extra
126 # bookkeeping) that the rest of the fields will be declared or
127 # have the same positions, so punt.
128 require Carp;
129 Carp::croak ("Reloaded module must declare all fields at once");
458fb581 130 }
f1192cee 131}
132
f30a1143 133sub inherit # called by base.pm when $base_fields is nonempty
f1192cee 134{
135 my($derived, $base) = @_;
f30a1143 136 my $base_attr = $attr{$base};
137 my $derived_attr = $attr{$derived} ||= [];
138 my $base_fields = \%{"$base\::FIELDS"};
139 my $derived_fields = \%{"$derived\::FIELDS"};
140
141 $derived_attr->[0] = $base_attr ? scalar(@$base_attr) : 1;
142 while (my($k,$v) = each %$base_fields) {
143 my($fno);
144 if ($fno = $derived_fields->{$k} and $fno != $v) {
145 require Carp;
146 Carp::croak ("Inherited %FIELDS can't override existing %FIELDS");
147 }
148 if ($base_attr->[$v] & _PRIVATE) {
149 $derived_attr->[$v] = undef;
150 } else {
151 $derived_attr->[$v] = $base_attr->[$v];
152 $derived_fields->{$k} = $v;
153 }
154 }
f1192cee 155}
156
157sub _dump # sometimes useful for debugging
158{
159 for my $pkg (sort keys %attr) {
160 print "\n$pkg";
ad78e549 161 if (@{"$pkg\::ISA"}) {
f1192cee 162 print " (", join(", ", @{"$pkg\::ISA"}), ")";
163 }
164 print "\n";
165 my $fields = \%{"$pkg\::FIELDS"};
166 for my $f (sort {$fields->{$a} <=> $fields->{$b}} keys %$fields) {
167 my $no = $fields->{$f};
168 print " $no: $f";
f30a1143 169 my $fattr = $attr{$pkg}[$no];
f1192cee 170 if (defined $fattr) {
171 my @a;
172 push(@a, "public") if $fattr & _PUBLIC;
173 push(@a, "private") if $fattr & _PRIVATE;
f30a1143 174 push(@a, "inherited") if $no < $attr{$pkg}[0];
f1192cee 175 print "\t(", join(", ", @a), ")";
176 }
177 print "\n";
178 }
179 }
458fb581 180}
181
1821;