This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Changes and README are not needed for Switch.pm
[perl5.git] / lib / base.pm
CommitLineData
dc6d0c4f
JH
1package base;
2
864f8ab4 3use strict 'vars';
dc6d0c4f 4use vars qw($VERSION);
9b6f3a27 5$VERSION = '2.08';
dc6d0c4f
JH
6
7# constant.pm is slow
8sub SUCCESS () { 1 }
9
10sub PUBLIC () { 2**0 }
11sub PRIVATE () { 2**1 }
12sub INHERITED () { 2**2 }
13sub PROTECTED () { 2**3 }
14
15
16my $Fattr = \%fields::attr;
17
18sub has_fields {
19 my($base) = shift;
20 my $fglob = ${"$base\::"}{FIELDS};
864f8ab4 21 return( ($fglob && *$fglob{HASH}) ? 1 : 0 );
dc6d0c4f
JH
22}
23
24sub has_version {
25 my($base) = shift;
26 my $vglob = ${$base.'::'}{VERSION};
864f8ab4 27 return( ($vglob && *$vglob{SCALAR}) ? 1 : 0 );
dc6d0c4f
JH
28}
29
30sub has_attr {
31 my($proto) = shift;
32 my($class) = ref $proto || $proto;
33 return exists $Fattr->{$class};
34}
35
36sub get_attr {
37 $Fattr->{$_[0]} = [1] unless $Fattr->{$_[0]};
38 return $Fattr->{$_[0]};
39}
40
8731c5d9
YK
41if ($] < 5.009) {
42 *get_fields = sub {
43 # Shut up a possible typo warning.
44 () = \%{$_[0].'::FIELDS'};
45 my $f = \%{$_[0].'::FIELDS'};
dc6d0c4f 46
8731c5d9
YK
47 # should be centralized in fields? perhaps
48 # fields::mk_FIELDS_be_OK. Peh. As long as %{ $package . '::FIELDS' }
49 # is used here anyway, it doesn't matter.
50 bless $f, 'pseudohash' if (ref($f) ne 'pseudohash');
51
52 return $f;
53 }
54}
55else {
56 *get_fields = sub {
57 # Shut up a possible typo warning.
58 () = \%{$_[0].'::FIELDS'};
59 return \%{$_[0].'::FIELDS'};
60 }
dc6d0c4f
JH
61}
62
dc6d0c4f
JH
63sub import {
64 my $class = shift;
65
66 return SUCCESS unless @_;
67
68 # List of base classes from which we will inherit %FIELDS.
69 my $fields_base;
70
71 my $inheritor = caller(0);
72
73 foreach my $base (@_) {
9b6f3a27
CP
74 if ( $inheritor eq $base ) {
75 warn "Class '$inheritor' tried to inherit from itself\n";
76 }
77
dc6d0c4f
JH
78 next if $inheritor->isa($base);
79
80 if (has_version($base)) {
81 ${$base.'::VERSION'} = '-1, set by base.pm'
82 unless defined ${$base.'::VERSION'};
83 }
84 else {
a7fce7e1 85 local $SIG{__DIE__};
dc6d0c4f
JH
86 eval "require $base";
87 # Only ignore "Can't locate" errors from our eval require.
88 # Other fatal errors (syntax etc) must be reported.
89 die if $@ && $@ !~ /^Can't locate .*? at \(eval /;
90 unless (%{"$base\::"}) {
91 require Carp;
92 Carp::croak(<<ERROR);
93Base class package "$base" is empty.
94 (Perhaps you need to 'use' the module which defines that package first.)
95ERROR
96
97 }
98 ${$base.'::VERSION'} = "-1, set by base.pm"
99 unless defined ${$base.'::VERSION'};
100 }
101 push @{"$inheritor\::ISA"}, $base;
102
dc6d0c4f 103 if ( has_fields($base) || has_attr($base) ) {
3c4b39be 104 # No multiple fields inheritance *suck*
864f8ab4
JH
105 if ($fields_base) {
106 require Carp;
107 Carp::croak("Can't multiply inherit %FIELDS");
108 } else {
109 $fields_base = $base;
dc6d0c4f
JH
110 }
111 }
112 }
113
114 if( defined $fields_base ) {
115 inherit_fields($inheritor, $fields_base);
116 }
117}
118
119
120sub inherit_fields {
121 my($derived, $base) = @_;
122
123 return SUCCESS unless $base;
124
125 my $battr = get_attr($base);
126 my $dattr = get_attr($derived);
127 my $dfields = get_fields($derived);
128 my $bfields = get_fields($base);
129
130 $dattr->[0] = @$battr;
131
132 if( keys %$dfields ) {
133 warn "$derived is inheriting from $base but already has its own ".
134 "fields!\n".
45e8908f 135 "This will cause problems.\n".
dc6d0c4f
JH
136 "Be sure you use base BEFORE declaring fields\n";
137 }
138
139 # Iterate through the base's fields adding all the non-private
140 # ones to the derived class. Hang on to the original attribute
141 # (Public, Private, etc...) and add Inherited.
142 # This is all too complicated to do efficiently with add_fields().
143 while (my($k,$v) = each %$bfields) {
144 my $fno;
145 if ($fno = $dfields->{$k} and $fno != $v) {
146 require Carp;
147 Carp::croak ("Inherited %FIELDS can't override existing %FIELDS");
148 }
149
150 if( $battr->[$v] & PRIVATE ) {
864f8ab4 151 $dattr->[$v] = PRIVATE | INHERITED;
dc6d0c4f
JH
152 }
153 else {
154 $dattr->[$v] = INHERITED | $battr->[$v];
dc6d0c4f
JH
155 $dfields->{$k} = $v;
156 }
157 }
864f8ab4 158
446e776f
DM
159 foreach my $idx (1..$#{$battr}) {
160 next if defined $dattr->[$idx];
161 $dattr->[$idx] = $battr->[$idx] & INHERITED;
864f8ab4 162 }
dc6d0c4f
JH
163}
164
165
1661;
167
168__END__
169
fb73857a 170=head1 NAME
171
45e8908f 172base - Establish IS-A relationship with base classes at compile time
fb73857a 173
174=head1 SYNOPSIS
175
176 package Baz;
fb73857a 177 use base qw(Foo Bar);
178
179=head1 DESCRIPTION
180
45e8908f
EM
181Allows you to both load one or more modules, while setting up inheritance from
182those modules at the same time. Roughly similar in effect to
fb73857a 183
45e8908f 184 package Baz;
fb73857a 185 BEGIN {
dc6d0c4f
JH
186 require Foo;
187 require Bar;
188 push @ISA, qw(Foo Bar);
fb73857a 189 }
190
45e8908f
EM
191If any of the listed modules are not loaded yet, I<base> silently attempts to
192C<require> them (and silently continues if the C<require> failed). Whether to
193C<require> a base class module is determined by the absence of a global variable
194$VERSION in the base package. If $VERSION is not detected even after loading
195it, <base> will define $VERSION in the base package, setting it to the string
196C<-1, set by base.pm>.
197
dc6d0c4f 198Will also initialize the fields if one of the base classes has it.
3c4b39be 199Multiple inheritance of fields is B<NOT> supported, if two or more
dc6d0c4f
JH
200base classes each have inheritable fields the 'base' pragma will
201croak. See L<fields>, L<public> and L<protected> for a description of
202this feature.
f1192cee 203
36c726b3
JB
204=head1 DIAGNOSTICS
205
206=over 4
207
208=item Base class package "%s" is empty.
209
210base.pm was unable to require the base package, because it was not
211found in your path.
212
213=back
214
b8bc843f
A
215=head1 HISTORY
216
fb73857a 217This module was introduced with Perl 5.004_04.
218
9b6f3a27
CP
219Attempting to inherit from yourself generates a warning:
220
221 use Foo;
222 use base 'Foo';
223
224 # Class 'Foo' tried to inherit from itself
fb73857a 225
dc6d0c4f 226=head1 CAVEATS
fb73857a 227
45e8908f 228Due to the limitations of the implementation, you must use
dc6d0c4f 229base I<before> you declare any of your own fields.
17f410f9 230
fb73857a 231
dc6d0c4f 232=head1 SEE ALSO
fb73857a 233
dc6d0c4f 234L<fields>
fb73857a 235
dc6d0c4f 236=cut