1package Class::Contract; 2use strict; 3use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS ); 4require Exporter; 5use Carp; 6 7$VERSION = '1.14'; 8 9@ISA = qw(Exporter); 10@EXPORT = qw(contract ctor dtor attr method pre impl post invar inherits 11 self value class abstract private optional check callstate 12 failmsg clon); 13@EXPORT_OK = qw(scalar_attrs array_attrs hash_attrs methods old); 14%EXPORT_TAGS = (DEFAULT => \@EXPORT, 15 EXTENDED => \@EXPORT_OK, 16 ALL => [@EXPORT, @EXPORT_OK]); 17 18my %contract; 19my %data; 20my %class_attr; 21my $current; 22my $msg_target; 23my %no_opt; # NOT IN PRODUCTION 24# $Class::Contract::hook = \%data; # for testing GC # NOT IN PRODUCTION 25 26my @class_dtors; 27END { $_->() foreach (@class_dtors) } 28 29my ($carp, $croak) = ( 30 sub { 31 my (@c) = caller(0); 32 ($c[3] eq 'Class::Contract::__ANON__') 33 ? print STDERR (@_, " at $c[1] line $c[2]\n") : &carp 34 }, 35 sub { 36 my (@c) = caller(0); 37 ($c[3] eq 'Class::Contract::__ANON__') 38 ? die(@_, " at $c[1] line $c[2]\n") : &croak 39 } 40); 41 42sub import { 43 my $class = $_[0]; 44 my $caller = caller; 45 $contract{$caller}{use_old} = grep(/^old$/, @_) ? 1 : 0; 46 push @_, @EXPORT; 47 no strict 'refs'; 48 INIT { 49 *{$caller .'::croak'} = $croak if defined *{$caller .'::croak'}{'CODE'}; 50 *{$caller .'::carp'} = $carp if defined *{$caller .'::carp'}{'CODE'}; 51 } 52 goto &Exporter::import; 53} 54 55sub unimport { 56 my $class = shift; 57 my $caller = caller; 58 $contract{$caller}{use_old} = 0 if grep /^old$/, @_; 59} 60 61sub contract(&) { $_[0]->(); _build_class(caller) } 62 63sub check(\%;$) { 64# NOT IN PRODUCTION... 65 my $state = !$#_ ? 0 : $_[1] ? 1 : 0; 66 defined $_ 67 or croak("Usage:\n\tcheck \%sentinel", 68 ($#_ ? " => $state" : ""), 69 " for ( \@classes );\n\n"); 70 71 my $forclass = $_; 72 $_[0]->{$forclass} = 73 bless { 'prev' => $no_opt{$forclass}, 74 'forclass' => $forclass }, 'Class::Contract::FormerState'; 75 $no_opt{$forclass} = $state; 76# ...NOT IN PRODUCTION 77} 78 79# NOT IN PRODUCTION... 80sub Class::Contract::FormerState { # No function signature? 81 $no_opt{$_[0]->{'forclass'}} = $_[0]->{'prev'}; # my ($self) = @_; 82} 83 84sub no_opt { # my ($class) = @_; 85 return exists $no_opt{$_[0]} ? $no_opt{$_[0]} 86 : exists $no_opt{'__ALL__'} ? $no_opt{'__ALL__'} 87 : 0; 88} 89# ...NOT IN PRODUCTION 90 91sub _location { # scalar context returns file and line of external code 92 # array context returns package aka 'owner', file and line 93 my ($i, @c, $owner); 94 while (@c = (caller($i++))[0..2]) { 95 if ($c[0] !~ /^Class::Contract$/) { 96 $owner = $c[0] if !$owner; 97 if ($c[1] !~ /^\(eval \d+\)$/) { 98 return (wantarray ? $owner : (), join ' line ', @c[1,2]); 99 } 100 } 101 } 102} 103 104my %def_type = ( 105 'attr' => 'SCALAR', 106 'method' => '', 107 'ctor' => '', 108 'dtor' => '', 109 'clon' => '', 110); 111 112sub _member { 113 my ($kind, $name, $type) = @_; 114 my ($owner, $location) = _location; 115 $name = '' unless $name; 116 117 if (defined $contract{$owner}{$kind}{$name}) { 118 croak "\u$kind ${owner}::$name redefined" if $name; 119 croak "Unnamed $kind redefined"; 120 } 121 122 $contract{$owner}{$kind}{$name} = $current = 123 bless {'name' => $name, 124 'type' => $type || $def_type{$kind}, 125 'gentype' => $type || $def_type{$kind}, # NOT IN PRODUCTION 126 'loc' => $location, 127 'shared' => 0, 128 'private' => 0, 129 'abstract' => 0, 130 'pre' => [], # NOT IN PRODUCTION 131 'post' => [], # NOT IN PRODUCTION 132 }, "Class::Contract::$kind"; 133 134 # NOT IN PRODUCTION... 135 $current->{'gentype'} = 'OBJECT' 136 unless $current->{'gentype'} =~ /\A(SCALAR|ARRAY|HASH)\z/; 137 # ...NOT IN PRODUCTION 138 return $current; 139} 140 141sub attr($;$) { _member('attr' => @_) } 142sub method($) { _member('method' => @_) } 143sub ctor(;$) { _member('ctor' => @_) } 144sub dtor() { _member('dtor') } 145sub clon() { _member('clone') } 146 147sub scalar_attrs(@) { map _member('attr', $_, 'SCALAR'), @_ } 148sub array_attrs(@) { map _member('attr', $_, 'ARRAY'), @_ } 149sub hash_attrs(@) { map _member('attr', $_, 'HASH'), @_ } 150sub methods(@) { map _member('attr', $_), @_ } 151 152sub class(@) { $_->{'shared'} = 1 foreach(@_); @_ } 153sub abstract(@) { $_->{'abstract'} = 1 foreach(@_); @_ } 154sub private(@) { $_->{'private'} = 1 foreach(@_); @_ } 155 156my %def_msg = ( 157 'pre' => 'Pre-condition at %s failed', 158 'post' => 'Post-condition at %s failed', 159 'invar' => 'Class invariant at %s failed', 160 'impl' => undef 161); 162 163sub _current { 164 my ($field, $code) = @_; 165 croak "Unattached $field" unless defined $current; 166 croak "Attribute cannot have implementation" 167 if $current->isa('Class::Contract::attr') && $field eq 'impl'; 168 169 my $descriptor = bless { 170 'code' => $code, 171 'opt' => 0, # NOT IN PRODUCTION 172 'msg' => $def_msg{$field}, 173 }, 'Class::Contract::current'; 174 @{$descriptor}{qw(owner loc)} = _location; 175 176 if ($field eq 'impl' && !( $current->isa('Class::Contract::ctor') 177 || $current->isa('Class::Contract::dtor') 178 || $current->isa('Class::Contract::clone') )) { 179 $current->{$field} = $descriptor 180 } else { 181 push @{$current->{$field}}, $descriptor 182 } 183 184 $msg_target = $descriptor; 185} 186 187sub failmsg { 188 croak "Unattached failmsg" unless $msg_target; 189 $msg_target->{'msg'} = shift; 190} 191 192sub pre(&) { _current('pre' => @_) } 193sub post(&) { _current('post' => @_) } 194sub impl(&) { _current('impl' => @_) } 195 196sub optional { # my (@descriptors) = @_; 197 $_->{'opt'} = 1 foreach(@_); @_ # NOT IN PRODUCTION 198} 199 200sub invar(&) { 201 my ($code) = @_; 202 203 my $descriptor = { 204 'code' => $code, 205 'opt' => 0, # NOT IN PRODUCTION 206 'msg' => $def_msg{'invar'}, 207 }; 208 @{$descriptor}{qw(owner loc)} = _location; 209 210 push @{$contract{$descriptor->{'owner'}}{'invar'}}, $descriptor; 211 $msg_target = $descriptor; 212} 213 214 215sub inherits(@) { 216 my ($owner) = _location; 217 foreach (@_) { 218 croak "Can't create circular reference in inheritence\n$_ is a(n) $owner" 219 if $_->isa($owner) 220 } 221 push @{$contract{$owner}{'parents'}}, @_; 222} 223 224sub _build_class($) { 225 my ($class) = @_; 226 my $spec = $contract{$class}; 227 _inheritance($class, $spec); 228 _attributes($class, $spec); 229 _methods($class, $spec); 230 _constructors($class, $spec); 231 _destructors($class, $spec); 232 _clones($class, $spec); 233 1; 234} 235 236localscope: { 237 my @context; 238 my %clear; # NOT IN PRODUCTION; 239 sub _set_context { 240 push @context, {'__SELF__' => shift}; 241 242 # NOT IN PRODUCTION... 243 my $proto = $context[-1]{__SELF__}; 244 my ($class, $obj) = ref($proto) 245 ? (ref($proto), $proto) 246 : ($proto, undef); 247 return if $class =~ /^Class::Contract::Old::_/; 248 249 if ($contract{$class}{'use_old'}) { 250 my $class_old = "Class::Contract::Old::_$#context"; 251 _pkg_copy($class, $class_old); 252 my $old = $class_old; 253 if ($obj) { 254 # Like generic_clone but into the cloned class 255 my $old_key = \ my $undef; 256 $old = bless \ $old_key, $class_old; 257 $data{$$old} = _dcopy($data{$$obj}) if exists $data{$$obj}; 258 } 259 $context[-1]{__OLD__} = $old; 260 } 261 # ...NOT IN PRODUCTION 262 } 263 sub _free_context { 264 return pop @context 265 } 266 sub old() { 267 croak "No context. Can't call &old" unless @context; 268 my $self = $context[-1]{__SELF__}; 269 my $class = ref($self) || $self; 270 croak "Support for &old has been toggled off" 271 unless ($contract{$class}{'use_old'}); 272 $context[-1]{__OLD__} # NOT IN PRODUCTION 273 } 274 275 my @value; 276 sub _set_value { push @value, \@_ } 277 sub _free_value { my $v = pop @value; wantarray ? @$v : $v->[0] } 278 279 sub value { 280 croak "Can't call &value " unless @value; 281 return $value[-1]; 282 } 283 284 sub self() { 285 if (@_) { 286 # NOT IN PRODUCTION... 287 croak "Usage:\tself(\$class_or_object)" 288 unless defined *{join(ref($_[0])||$_[0], '::')}; 289 # ...NOT IN PRODUCTION 290 $context[-1]{__SELF__} = shift; 291 } 292 croak "No context. Can't call &self" unless @context; 293 $context[-1]{__SELF__} 294 } 295 296 sub callstate() { 297 croak "No context. Can't call &callstate" unless @context; 298 return $context[-1]; 299 } 300} 301 302sub _inheritance { # A D Invokation order 303# Inheritence is left-most depth-first. Destructors # /\ | 304# are called in reversed order as the constructors # B C E ctor: ABCDEF 305# Diamond patterns in inheritence are 'handled' by # \// dtor: FEDCBA 306# looking for and skipping duplicate anonymous refs # F 307 308 my ($classname, $spec) = @_; 309 my (%inherited_clause, %inherited_impl); 310 foreach my $ancestor ( reverse @{$spec->{'parents'} || [] } ) { 311 my $parent = $contract{$ancestor} || next; 312 if ($parent->{'use_old'} and not $spec->{'use_old'}) { 313 croak("Derived class $classname, has not toggled on support for ->old\n", 314 "which is required by ancestor $ancestor. Did you forget to\n", 315 "declare: use Class::Contract 'old'; ?"); 316 } 317 foreach my $clause ( qw( attr method ctor clone dtor ) ) { 318 foreach my $name ( keys %{ $parent->{$clause} || {} } ) { 319 # Inherit each clause from ancestor unless defined 320 if (! defined $spec->{$clause}{$name} 321 and not exists $inherited_clause{$name}) { 322 $inherited_clause{$name}++; 323 %{$spec->{$clause}{$name}} = (%{$parent->{$clause}{$name}}); 324 $spec->{$clause}{$name}{'pre'} = []; # NOT IN PRODUCTION 325 next; 326 } 327 328 # Inherit ctor/clone/dtor invokation from ancestors 329 if ($clause =~ /^(ctor|clone|dtor)$/) { 330 if (defined $parent->{$clause}{$name}{'impl'} 331 and @{$parent->{$clause}{$name}{'impl'}}) { 332 my (@impl, %seen) = (@{$spec->{$clause}{$name}{'impl'}}); 333 if (@impl) { 334 $seen{$impl[$_]} = $_ foreach (0..$#impl); 335 foreach my $item ( @{$parent->{$clause}{$name}{'impl'}} ) { 336 splice(@{$spec->{$clause}{$name}{'impl'}}, $seen{$item}, 1) 337 if exists $seen{$item}; 338 } 339 } 340 $clause ne 'dtor' 341 ? unshift(@{$spec->{$clause}{$name}{'impl'}}, 342 @{$parent->{$clause}{$name}{'impl'}}) 343 : push(@{$spec->{$clause}{$name}{'impl'}}, 344 @{$parent->{$clause}{$name}{'impl'}}); 345 } 346 } 347 348 # Get implementation from ancestor if derived but not redefined 349 if ($clause eq 'method') { 350 if (! defined $spec->{$clause}{$name}{'impl'} 351 or $inherited_impl{$name}) { 352 $inherited_impl{$name}++; 353 $spec->{$clause}{$name}{'impl'}=$parent->{$clause}{$name}{'impl'}; 354 } 355 croak("Forget 'private'? $classname inherits private $name from ", 356 "$ancestor\n") 357 if ($parent->{$clause}{$name}{'private'} 358 and not $spec->{$clause}{$name}{'private'}) 359 } 360 # NOT IN PRODUCTION... 361 # Inherit all post-conditions from ancestors 362 if (@{$parent->{$clause}{$name}{'post'}||[]}) { 363 my (@post, %seen) = (@{$spec->{$clause}{$name}{'post'}}); 364 if (@post) { 365 $seen{$post[$_]} = $_ foreach (0..$#post); 366 foreach my $item ( @{$parent->{$clause}{$name}{'post'}} ) { 367 splice(@{$spec->{$clause}{$name}{'post'}}, $seen{$item}, 1) 368 if exists $seen{$item}; 369 } 370 } 371 push(@{$spec->{$clause}{$name}{'post'}}, 372 @{$parent->{$clause}{$name}{'post'}}); 373 } 374 # ...NOT IN PRODUCTION 375 } 376 } 377 # NOT IN PRODUCTION... 378 # Inherit all class invariants from ancestors 379 if (defined $parent->{'invar'} and @{$parent->{'invar'}}) { 380 defined $spec->{'invar'} or $spec->{'invar'} = []; 381 my (@invar, %seen) = (@{$spec->{'invar'}}); 382 if (@invar) { 383 $seen{$invar[$_]} = $_ foreach (0..$#invar); 384 foreach (@{$parent->{'invar'}}) { 385 splice(@{$spec->{'invar'}}, $seen{$_}, 1) if exists $seen{$_} 386 } 387 } 388 push @{$spec->{'invar'}}, @{$parent->{'invar'}}; 389 } 390 # ...NOT IN PRODUCTION 391 } 392 393 no strict 'refs'; 394 unshift @{"${classname}::ISA"}, @{ $spec->{'parents'} || [] }; 395} 396 397sub _attributes { 398 my ($classname, $spec) = @_; 399 400 while ( my ($name, $attr) = each %{$spec->{'attr'}} ) { 401 if ($attr->{'shared'}) { 402 my $ref = $class_attr{$classname}{$name} = 403 $attr->{'type'} eq 'ARRAY' ? [] 404 : $attr->{'type'} eq 'HASH' ? {} 405 : $attr->{'type'} eq 'SCALAR' ? do { \ my $scalar } 406 : eval { $attr->{'type'}->new } 407 || croak "Unable to create $attr->{'type'} object ", 408 "for class attribute $name"; 409 } 410 411 localscope: { 412 no strict 'refs'; 413 local $^W; 414 *{"${classname}::$name"} = sub { 415 croak(qq|Can\'t access object attr w/ class reference |,$attr->{'loc'}) 416 unless ($attr->{'shared'} or ref($_[0])); 417 418 my $caller = caller; 419 croak "attribute ${classname}::$name inaccessible from package $caller" 420 unless $classname->isa($caller); 421 422 my $self = shift; 423 _set_context(($attr->{'shared'} ? ref($self)||$self : $self), 424 join ' line ', [caller]->[1,2]); 425 my $attr_ref = ($attr->{'shared'}) 426 ? $class_attr{$classname}{$name} 427 : $data{$$self}{$name}; 428 _set_value $attr_ref; 429 430 # NOT IN PRODUCTION... 431 my @fail = generic_check('pre', 'attr' => $name, $spec); 432 croak @fail if @fail; 433 # ...NOT IN PRODUCTION 434 435 _free_context; 436 437 # NOT IN PRODUCTION... 438 return "Class::Contract::Post$attr->{'gentype'}"->new( 439 $attr->{'post'}, $attr_ref, $name, 440 ) if @{$attr->{'post'}}; 441 # ...NOT IN PRODUCTION 442 443 scalar _free_value; 444 return $attr_ref; 445 }; 446 } 447 } 448} 449 450sub _methods { 451 my ($classname, $spec) = @_; 452 453 while ( my ($name, $method) = each %{$spec->{'method'}} ) { 454 $spec->{'abstract'} ||= $method->{'abstract'}; 455 unless ($method->{'impl'}) { 456 if ($method->{'abstract'}) { 457 $method->{'impl'} = {'code' => sub { 458 croak "Can't call abstract method ${classname}::$name" 459 } } 460 } else { 461 croak qq{No implementation for method $name at $method->{'loc'}.\n}, 462 qq{(Did you forget to declare it 'abstract'?)\n} 463 } 464 } 465 466 local_scope: { 467 local $^W; 468 no strict 'refs'; 469 *{"${classname}::$name"} = sub { 470 my $caller = caller; 471 croak("private method ${classname}::$name inaccessible from ", 472 scalar caller) 473 if ($method->{'private'} 474 and not ($classname->isa($caller))); # or $caller->isa($classname))); 475 476 my $self = shift; 477 _set_context(($method->{'shared'} ? ref($self)||$self : $self), 478 join ' line ', [caller]->[1,2]); 479 480 # NOT IN PRODUCTION... 481 croak(qq|Can\'t invoke object method w/ class name |, $method->{'loc'}) 482 unless ($method->{'shared'} or ref($self)); 483 484 my $no_opt = no_opt($classname); 485 my @fail = generic_check('pre', 'method' => $name, $spec, @_); 486 croak @fail if @fail; 487 # ...NOT IN PRODUCTION 488 489 _set_value wantarray 490 ? $method->{'impl'}{'code'}->(@_) 491 : scalar $method->{'impl'}{'code'}->(@_); 492 493 # NOT IN PRODUCTION... 494 generic_check('post', 'method' => $name, $spec, @_); 495 generic_check('invar', 'method' => $name, $spec, @_) 496 if (caller ne $classname); 497 # ...NOT IN PRODUCTION 498 499 _free_context; 500 _free_value; 501 }; 502 } 503 } 504} 505 506# NOT IN PRODUCTION... 507sub generic_check { 508 return if (ref(self)||self) =~ /^Class::Contract::Old::_/; 509 510 my ($type, $kind, $name, $class_spec, @args) = @_; 511 my @specs = @{$class_spec->{$kind}{$name}{$type}||[]}; 512 my @errors; 513 514 foreach my $spec ( @specs ) { 515 next if $spec->{'opt'} && no_opt($spec->{'owner'}) 516 || $spec->{'code'}->(@args); 517 push @errors, sprintf($spec->{'msg'},$spec->{'loc'})."\n"; 518 } 519 520 @errors ? croak @errors : return unless $type eq 'pre'; 521 return if @specs && !@errors; 522 523 # OTHERWISE SATISFY AT LEAST ONE PARENT? 524 foreach my $ancestor ( @{$class_spec->{'parents'}||[]} ) { 525 my $parent = $contract{$ancestor}; 526 next unless exists $parent->{$kind}{$name}; 527 my $has_pre = scalar @{$parent->{$kind}{$name}{'pre'}}; 528 unless ($has_pre) { 529 foreach my $p (@{$parent->{'parents'}||[]}) { 530 $has_pre++ and last if _hasa($p, $kind, $name, 'pre'); 531 } 532 } 533 534 if ($has_pre) { 535 my @par_err = generic_check($type, $kind, $name, $parent, @args); 536 return unless @par_err; 537 push @errors, @par_err; 538 } 539 } 540 return @errors; 541} 542 543sub _hasa { 544 my ($class, $kind, $name, $type) = (@_); 545 return 0 unless defined $contract{$class}{$kind}{$name}; 546 547 my $has = @{$contract{$class}{$kind}{$name}{$type} || []} ? 1 : 0; 548 unless ($has) { 549 foreach my $ancestor (@{$contract{$class}{'parents'} || []}) { 550 $has++ and last if _hasa($ancestor, $kind, $name, $type); 551 } 552 } 553 return $has; 554} 555# ...NOT IN PRODUCTION 556 557sub generic_ctor { 558 my ($class) = @_; 559 560 croak "Class $class has abstract methods. Can't create $class object" 561 if $contract{$class}{'abstract'}; 562 563 my $key = \ my $undef; 564 my $obj = \ $key; 565 bless $obj, $class; 566 567 my $attr = $contract{$class}{'attr'}; 568 569 foreach my $attrname ( keys %$attr ) { 570 unless ($attr->{$attrname} && $attr->{$attrname}{'shared'}) { 571 my $ref = $data{$key}{$attrname} 572 = $attr->{$attrname}{'type'} eq 'ARRAY' ? [] 573 : $attr->{$attrname}{'type'} eq 'HASH' ? {} 574 : $attr->{$attrname}{'type'} eq 'SCALAR' ? do { \my $scalar } 575 : eval { $attr->{$attrname}{type}->new } 576 || croak "Unable to create $attr->{$attrname}{'type'} ", 577 "object for attribute $attrname"; 578 } 579 } 580 581 return $obj; 582} 583 584sub generic_clone ($) { 585 my $self = shift; 586 my $ref = ref($self); 587 croak "usage: \$object->clone -Invalid arg $self" 588 unless ($ref and 589 $ref !~ /^(HASH|ARRAY|SCALAR|GLOB|FORMAT|CODE|Regexp|REF)$/); 590 my $key = \ my $undef; 591 my $obj = bless \$key, $ref; 592 $data{$key} = _dcopy($data{$$self}) if exists $data{$$self}; 593 return $obj; 594} 595 596 597sub _constructors { 598 my ($classname, $spec) = @_; 599 my $noctor = 1; 600 601 while ( my ($name, $ctor) = each %{$spec->{'ctor'}} ) { 602 $noctor &&= $ctor->{'shared'} 603 } 604 605 $spec->{'ctor'}{'new'} = bless { 606 'name' => 'new', 607 'shared' => 0, 608 'abstract' => 0, 609 'loc' => '<implicit>' 610 }, 'Class::Contract::ctor' 611 if $noctor; 612 613 while ( my ($name, $ctor) = each %{$spec->{'ctor'}} ) { 614 $spec->{'abstract'} ||= $ctor->{'abstract'}; 615 616 if ($ctor->{'shared'}) { 617 localscope: { 618 local $^W; 619 no strict 'refs'; 620 my $classctor = sub { 621 my $self = shift; 622 _set_context ref($self)||$self; 623 624 # NOT IN PRODUCTION... 625 my @fail = generic_check('pre', 'ctor' => $name, $spec, @_); 626 croak @fail if @fail; 627 # ...NOT IN PRODUCTION 628 629 $_->{'code'}->(@_) foreach ( @{$ctor->{'impl'}} ); 630 631 # NOT IN PRODUCTION... 632 generic_check('post', 'ctor' => $name, $spec, @_); 633 generic_check('invar','ctor' => $name, $spec, @_) 634 if (caller ne $classname); 635 # ...NOT IN PRODUCTION 636 637 _free_context; 638 }; 639 $classname->$classctor(); 640# *{"${classname}::$name"} = $classctor if $name; 641 } 642 } else { 643 localscope:{ 644 local $^W; 645 no strict 'refs'; 646 *{"${classname}::$name"} = sub { 647 my $proto = shift; 648 my $class = ref($proto)||$proto; 649 my $self = Class::Contract::generic_ctor($class); 650 _set_context $self; 651 652 # NOT IN PRODUCTION... 653 my @fail = generic_check('pre', 'ctor' => $name, $spec, @_); 654 croak @fail if @fail; 655 # ...NOT IN PRODUCTION 656 657 $_->{'code'}->(@_) foreach ( @{$ctor->{'impl'}} ); 658 659 # NOT IN PRODUCTION... 660 generic_check('post', 'ctor' => $name, $spec, @_); 661 generic_check('invar','ctor' => $name, $spec, @_) 662 if (caller ne $classname); 663 # ...NOT IN PRODUCTION 664 665 _free_context; 666 return $self; 667 } 668 } 669 } 670 } 671} 672 673use Data::Dumper; 674sub _destructors { 675 676 my ($classname, $spec) = @_; 677 my $dtorcount = 0; 678 679 while ( my ($name, $dtor) = each %{$spec->{'dtor'}} ) { 680 $spec->{'abstract'} ||= $dtor->{'abstract'}; 681 682 if ($dtor->{'shared'}) { 683 localscope: { 684 local $^W; 685 no strict 'refs'; 686 my $classdtor = sub { 687 croak "Illegal explicit invokation of class dtor", $dtor->{'loc'} 688 if caller() ne 'Class::Contract'; 689 my $self = shift; 690 $self = ref $self if ref $self; 691 692 _set_context $self; 693 694 # NOT IN PRODUCTION... 695 my @fail = generic_check('pre', 'dtor' => $name, $spec, @_); 696 croak @fail if @fail; 697 # ...NOT IN PRODUCTION 698 699 $_->{'code'}->(@_) foreach ( @{$dtor->{'impl'}} ); 700 701 generic_check('post', 'dtor' => $name, $spec, @_);# NOT IN PRODUCTION 702 _free_context; 703 }; 704 705 push @class_dtors, sub { $classname->$classdtor() }; 706 } 707 } else { 708 croak "Class $classname has too many destructors" if $dtorcount++; 709 710 localscope: { 711 local $^W; 712 no strict 'refs'; 713 my $objdtor = sub { 714 croak "Illegal explicit invokation of object dtor", $dtor->{'loc'} 715 if caller() ne 'Class::Contract'; 716 717 my $self = shift; 718 _set_context $self; 719 720 # NOT IN PRODUCTION... 721 my @fail = generic_check('pre', 'dtor' => $name, $spec, @_); 722 croak @fail if @fail; 723 # ...NOT IN PRODUCTION 724 725 $_->{'code'}->(@_) foreach ( @{$dtor->{'impl'}||[]} ); 726 727 # NOT IN PRODUCTION... 728 generic_check('post', 'dtor' => $name, $spec, @{[@_]}); 729 generic_check('invar', 'dtor' => $name, $spec, @{[@_]}) 730 if (caller ne $classname); 731 # ...NOT IN PRODUCTION 732 733 _free_context; 734 return; 735 }; 736 737 *{"${classname}::DESTROY"} = sub { 738 $_[0]->$objdtor(); 739 delete $data{${$_[0]}} if exists $data{${$_[0]}}; 740 }; 741 } 742 } 743 } 744 unless (defined &{"${classname}::DESTROY"}) { 745 local $^W; 746 no strict 'refs'; 747 *{"${classname}::DESTROY"} = sub { 748 delete $data{${$_[0]}} if exists $data{${$_[0]}}; 749 }; 750 } 751} 752 753sub _clones { 754 my ($classname, $spec) = @_; 755 my $clone_count = 0; 756 757 $spec->{'clone'}{''} = bless { 758 'name' => '', 759 'shared' => 0, 760 'abstract' => 0, 761 'loc' => '<implicit>' 762 }, 'Class::Contract::clone' 763 unless $spec->{'clone'}; 764 765 while ( my ($name, $clause) = each %{$spec->{'clone'}} ) { 766 767 $spec->{'abstract'} ||= $clause->{'abstract'}; 768 croak "'class' clause can not be used to qualify 'clon'" 769 if $clause->{'shared'}; 770 croak "too many clon clauses" if $clone_count++; 771 772 localscope: { 773 local $^W; 774 no strict 'refs'; 775 *{"${classname}::clone"} = sub { 776 my $self = shift; 777 $self = generic_clone($self); 778 _set_context $self; 779 780 # NOT IN PRODUCTION... 781 my @fail = generic_check('pre', 'dtor' => $name, $spec, @_); 782 croak @fail if @fail; 783 # ...NOT IN PRODUCTION 784 785 $_->{'code'}->(@_) foreach ( @{$clause->{'impl'}||[]} ); 786 787 # NOT IN PRODUCTION... 788 generic_check('post', $clause => $name, $spec, @{[@_]}); 789 generic_check('invar', $clause => $name, $spec, @{[@_]}) 790 if (caller ne $classname); 791 # ...NOT IN PRODUCTION 792 793 _free_context; 794 return $self; 795 }; 796 } 797 } 798} 799 800localscope: { 801 my ($a,$z) = (qr/(^|^.*?=)/, qr/\(.*?\)$/); 802 my %seen = (); 803 my $depth = 0; 804 sub _dcopy { # Dereference and return a deep copy of whatever's passed 805 my ($r, $ref, $rval); 806 $ref = ref($_[0]) or return $_[0]; 807 exists $seen{$_[0]} and return $seen{$_[0]}; 808 $depth++; 809 810 $r = 811 ($_[0] =~ /${a}HASH$z/) ? {map _dcopy($_), (%{$_[0]})} 812 : ($_[0] =~ /${a}ARRAY$z/) ? [map _dcopy($_), @{$_[0]} ] 813 : ($_[0] =~ /${a}SCALAR$z/) ? do { my $v = _dcopy(${$_[0]}); \$v } 814 : ($_[0] =~ /${a}FORMAT$z/) ? $_[0] 815 : ($_[0] =~ /${a}CODE$z/) ? $_[0] 816 : ($_[0] =~ /${a}Regexp$z/) ? $_[0] 817 : ($_[0] =~ /${a}REF$z/) ? $_[0] 818 : ($_[0] =~ /${a}GLOB$z/) ? $_[0] 819 : $_[0]->can('clone') ? $_[0]->clone : $_[0]; 820 821 $rval = $ref =~ /^(HASH|ARRAY|SCALAR|GLOB|FORMAT|CODE|Regexp|REF)$/ 822 ? $r 823 : bless $r, $ref; 824 825 --$depth 826 and $seen{$_[0]} = $rval 827 or %seen = (); 828 829 return $rval; 830 } 831} 832 833# NOT IN PRODUCTION... 834sub _pkg_copy ($$) { # $from_package, $to_package 835 no strict 'refs'; 836 defined *{$_[0] . '::'} 837 or croak "_pkg_copy() Can't clone from non-existant package $_[0]"; 838 defined *{$_[1] . '::'} and *{$_[1] . '::'} = {}; 839 840 foreach my $glob (values %{*{$_[0] . '::'}}) { 841 my ($varname) = $glob =~ /^\*$_[0]::(.*)/ or next; 842 foreach my $slot (qw(SCALAR ARRAY HASH CODE FORMAT)) { 843 my $ref = _dcopy(*{"$_[0]::$varname"}{$slot}); 844 *{"$_[1]::$varname"} = $ref if defined $ref; 845 } 846 } 847} 848 849sub _pkg_clear ($) { 850 no strict 'refs'; 851 my ($package) = shift; 852 my $stash = *{$package . '::'}{HASH}; 853 foreach my $name (keys %$stash) { 854 $name = join('::', $package, $name); 855# print "undef $name\n"; 856 undef $$name; 857 undef @$name; 858 undef %$name; 859 860 undef &$name; 861 undef *$name; 862 } 863 undef %{$package . '::'}; 864} 865 866sub Class::Contract::PostOBJECT::new { 867 my ($class, $posts, $original, $name) = @_; 868 my $objclass = ref $original; 869 carp("Warning: cannot check post-condition", 870 (@$posts==1?"":'s'), 871 " on $objclass attribute '$name'") 872 if $^W; 873 _free_value; 874 return $original; 875} 876 877package Class::Contract::PostSCALAR; 878 879sub new { 880 my $proxy; 881 tie $proxy, 'Class::Contract::PostSCALAR', @_; 882 return \$proxy; 883} 884 885sub TIESCALAR { 886 my ($class, $self, $postsubs, $original) = @_; 887 return bless { 888 'orig' => $original, 889 'post' => $postsubs, 890 }, $class; 891} 892 893sub FETCH { return ${$_[0]->{'orig'}} } 894sub STORE { ${$_[0]->{'orig'}} = $_[1] } 895 896sub DESTROY { 897 Class::Contract::generic_check('post', 'attr', @{self()}{qw(orig spec)}, @_); 898 Class::Contract::_free_value(); 899} 900 901package Class::Contract::PostARRAY; 902 903sub new { 904 my @proxy; 905 tie @proxy, 'Class::Contract::PostARRAY', @_; 906 if ($_[3]) { bless \@proxy, ref $_[2] } 907 return \@proxy; 908} 909 910sub TIEARRAY { 911 my ($class, $self, $postsubs, $original) = @_; 912 return bless { 'orig' => $original, 913 'post' => $postsubs, 914 }, $class; 915} 916 917sub FETCH { $_[0]->{'orig'}->[$_[1]] } 918sub FETCHSIZE { scalar @{$_[0]->{'orig'}} } 919sub STORE { $_[0]->{'orig'}->[$_[1]] = $_[2] } 920sub STORESIZE { $#{$_[0]->{'orig'}} = $_[1]-1 } 921sub EXTEND { $#{$_[0]->{'orig'}} = $_[1]-1 } 922sub CLEAR { @{$_[0]->{'orig'}} = () } 923sub PUSH { push @{$_[0]->{'orig'}}, @_[1..$#_] } 924sub POP { pop @{$_[0]->{'orig'}} } 925sub UNSHIFT { unshift @{$_[0]->{'orig'}}, @_[1..$#_] } 926sub SHIFT { shift @{$_[0]->{'orig'}} } 927 928sub DESTROY { 929 Class::Contract::generic_check('post', 'attr', @{self()}{qw(orig spec)}, @_); 930 Class::Contract::_free_value(); 931} 932 933 934package Class::Contract::PostHASH; 935 936sub new { 937 my %proxy; 938 tie %proxy, 'Class::Contract::PostHASH', @_; 939 if ($_[3]) { bless \%proxy, ref $_[2] } 940 return \%proxy; 941} 942 943sub TIEHASH { 944 my ($class, $self, $postsubs, $original) = @_; 945 return bless { 'orig' => $original, 946 'post' => $postsubs, 947 }, $class; 948} 949 950sub FETCH { $_[0]->{'orig'}->{$_[1]} } 951sub STORE { $_[0]->{'orig'}->{$_[1]} = $_[2] } 952sub EXISTS { exists $_[0]->{'orig'}->{$_[1]} } 953sub DELETE { delete $_[0]->{'orig'}->{$_[1]} } 954sub CLEAR { %{$_[0]->{'orig'}} = () } 955sub FIRSTKEY { keys %{$_[0]->{'orig'}}; each %{$_[0]->{'orig'}} } 956sub NEXTKEY { each %{$_[0]->{'orig'}} } 957 958sub DESTROY { 959 Class::Contract::generic_check('post', 'attr', @{self()}{qw(orig spec)}, @_); 960 Class::Contract::_free_value(); 961} 962# ...NOT IN PRODUCTION 963 9641; 965 966__END__ 967 968=head1 NAME 969 970Class::Contract - Design-by-Contract OO in Perl. 971 972=head1 VERSION 973 974This document describes version 1.10 of Class::Contract, 975released February 9, 2001. 976 977=head1 SYNOPSIS 978 979 package ClassName 980 use Class::Contract; 981 982 contract { 983 inherits 'BaseClass'; 984 985 invar { ... }; 986 987 attr 'data1'; 988 attr 'data2' => HASH; 989 990 class attr 'shared' => SCALAR; 991 992 ctor 'new'; 993 994 method 'methodname'; 995 pre { ... }; 996 failmsg 'Error message'; 997 998 post { ... }; 999 failmsg 'Error message'; 1000 1001 impl { ... }; 1002 1003 method 'nextmethod'; 1004 impl { ... }; 1005 1006 class method 'sharedmeth'; 1007 impl { ... }; 1008 1009 # etc. 1010 }; 1011 1012 1013=head1 DESCRIPTION 1014 1015=head2 Background 1016 1017Design-by-contract is a software engineering technique in which each 1018module of a software system specifies explicitly what input (or data or 1019arguments) it requires, and what output (or information or results) it 1020guarantees to produce in response. 1021 1022These specifications form the "clauses" of a contract between a 1023module and the client software that uses it. If the client software 1024abides by the input requirements, the module guarantees to produce 1025the correct output. Hence by verifying these clauses at each 1026interaction with a module, the overall behaviour of the system can 1027be confidently predicted. 1028 1029Design-by-contract reinforces the benefits of modular design techniques 1030by inserting explicit compile-time or run-time checks on a contract. 1031These checks are most often found in object-oriented languages 1032and are typically implemented as pre-conditions and post-conditions 1033on methods, and invariants on classes. 1034 1035Note that these features differ from simple verification statements 1036such as the C C<assert> statement. Conditions and invariants are 1037properties of a class, and are inherited by derived classes. 1038 1039An additional capacity that is often provided in design-by-contract 1040systems is the ability to selectively disable checking in production 1041code. This allows the contractual testing to be carried out 1042during implementation, without impinging on the performance of 1043the final system. 1044 1045=head2 Adding design-by-contract to Perl 1046 1047The Class::Contract module provides a framework for specifying 1048methods and attributes for a class (much like the existing class 1049definition modules Class::Struct, Class::MethodMaker, and 1050Class::Generate). Class::Contract allows both per-object and per-class 1051methods and attributes to be defined. Attributes may be scalar-, array-, 1052hash-, or object-based. 1053 1054Class::Contract differs from other class-specification modules (except 1055Class::Generate) in that it also provides the ability to specify 1056invariant conditions on classes, and pre- and post-conditions on methods 1057and attributes. All of these clauses are fully inheritable, and may be 1058selectively disabled. It differs from all other modules in that it has a 1059cleaner, simpler specification syntax, and -- more importantly -- it 1060enforces encapsulation of object attributes, thereby ensuring that the 1061class contract cannot be subverted. 1062 1063 1064=head2 Defining classes 1065 1066Class::Contract provides an explicit syntax for defining the attributes, 1067methods, and constructors of a class. The class itself is defined using 1068the C<contract> subroutine. C<contract> takes a single argument -- a 1069subroutine reference or a block. That block is executed once and the 1070results used to construct and install the various components of the 1071class in the current package: 1072 1073 package Queue; 1074 contract { 1075 # specification of class Queue attributes and methods here 1076 }; 1077 1078=head2 Defining attributes 1079 1080Attributes are defined within the C<contract> block via the C<attr> subroutine. 1081Attributes must be given a name, and may also be given a type: C<SCALAR>, 1082C<ARRAY>, C<HASH>, or a class name: 1083 1084 contract { 1085 attr 'last'; # Scalar attribute (by default) 1086 attr 'lest' => SCALAR; # Scalar attribute 1087 attr 'list' => ARRAY; # Array attribute 1088 attr 'lost' => HASH; # Hash attribute 1089 attr 'lust' => MyClass; # Object attribute 1090 }; 1091 1092For each attribute so declared, Class::Contract creates an I<accessor> -- a 1093method that returns a reference to the attribute in question. Code using these 1094accessors might look like this: 1095 1096 ${$obj->last}++; 1097 push @{$obj->list}, $newitem; 1098 print $obj->lost->{'marbles'}; 1099 $obj->lust->after('technology stocks'); 1100 1101Attributes are normally object-specific, but it is also possible to define 1102attributes that are shared by all objects of a class. Class objects are 1103specified by prefixing the call to C<attr> with a call to the C<class> 1104subroutine: 1105 1106 class Queue; 1107 contract { 1108 class attr 'obj_count'; 1109 }; 1110 1111The accessor for this shared attribute can now be called either as an 1112object method: 1113 1114 print ${$obj->obj_count}; 1115 1116or as a class method: 1117 1118 print ${Queue->obj_count}; 1119 1120In order to ensure that the clauses of a class' contract (see below) 1121are honoured, both class and object attributes are only accessible via 1122their accessors, and those accessors may only be called within methods 1123belonging to the same class hierarchy. Objects are implemented as 1124"flyweight scalars" in order to ensure this strict encapsulation is 1125preserved. 1126 1127=head2 Defining methods 1128 1129Methods are defined in much the same way as attributes. The C<method> 1130subroutine is used to specify the name of a method, then the C<impl> 1131subroutine is used to provide an implementation for it: 1132 1133 contract { 1134 attr list => ARRAY; 1135 1136 method 'next'; 1137 impl { shift @{self->list} }; 1138 1139 method 'enqueue'; 1140 impl { push @{self->list}, $_[1] }; 1141 }; 1142 1143C<impl> takes a block (or a reference to a subroutine), which is used as 1144the implementation of the method named by the preceding C<method> call. 1145Within that block, the subroutine C<self> may be used to return a 1146reference to the object on which the method was called. Unlike, regular 1147OO Perl, the object reference is not passed as the method's first argument. 1148(Note: this change occurred in version 1.10) 1149 1150Like attributes, methods normally belong to -- and are accessed via -- a 1151specific object. To define methods that belong to the entire class, the 1152C<class> qualifier is once again used: 1153 1154 contract { 1155 class attr 'obj_count'; 1156 1157 class method 'inc_count'; 1158 impl { ${self->obj_count}++ }; 1159 }; 1160 1161Note that the C<self> subroutine can still be used -- within a class 1162method it returns the appropriate class name, rather than an object 1163reference. 1164 1165=head2 Defining constructors 1166 1167Class::Contract requires constructors to be explicitly defined using 1168the C<ctor> subroutine: 1169 1170 contract { 1171 ctor 'new'; 1172 impl { @{self->list} = ( $_[0] ) } 1173 }; 1174 1175Note that the implementation section of a constructor I<doesn't> specify 1176code to build or bless the new object. That is taken care of 1177automatically (in order to ensure the correct "flyweight" 1178implementation of the object). 1179 1180Instead, the constructor implementation is invoked I<after> the object 1181has been created and blessed into the class. Hence the implementation 1182only needs to initialize the various attributes of the C<self> object. 1183In addition, the return value of the implementation is ignored: 1184constructor calls always return a reference to the newly created object. 1185 1186Any attribute that is not initialized by a constructor is 1187automatically "default initialized". By default, scalar attributes 1188remain C<undef>, array and hash attributes are initialized to an empty 1189array or hash, and object attributes are initialized by having their 1190C<new> constructor called (with no arguments). This is the only 1191reasonable default for object attributes, but it is usually advisable to 1192initialize them explicitly in the constructor. 1193 1194It is also possible to define a "class constructor", which may be used 1195to initialize class attributes: 1196 1197 contract { 1198 class attr 'obj_count'; 1199 1200 class ctor; 1201 impl { ${self->obj_count} = 0 }; 1202 }; 1203 1204The class constructor is invoked at the very end of the call to 1205C<contract> in which the class is defined. 1206 1207Note too that the class constructor does not require a name. It may, 1208however, be given one, so that it can be explicitly called again (as a 1209class method) later in the program: 1210 1211 class MyClass; 1212 contract { 1213 class attr 'obj_count'; 1214 1215 class ctor 'reset'; 1216 impl { ${self->obj_count} = 0 }; 1217 }; 1218 1219 # and later... 1220 1221 MyClass->reset; 1222 1223 1224=head2 Defining destructors 1225 1226Destructors are also explicitly defined under Class::Contract, 1227using the C<dtor> subroutine: 1228 1229 contract { 1230 dtor; 1231 impl { print STDLOG "Another object died\n" } 1232 }; 1233 1234As with the constructor, the implementation section of a destructor 1235doesn't specify code to clean up the "flyweight" implementation of 1236the object. Class::Contract takes care of that automatically. 1237 1238Instead, the implementation is invoked I<before> the object is 1239deallocated, and may be used to clean up any of the internal structure 1240of the object (for example to break reference cycles). 1241 1242It is also possible to define a "class destructor", which may be used 1243to clean up class attributes: 1244 1245 contract { 1246 class attr 'obj_count'; 1247 1248 class dtor; 1249 impl { print STDLOG "Total was ${self->obj_count}\n" }; 1250 }; 1251 1252The class destructor is invoked from an C<END> block within Class::Contract 1253(although the implementation itself is a closure, so it executes in the 1254namespace of the original class). 1255 1256 1257=head2 Constraining class elements 1258 1259As described so far, Class::Contract doesn't provide any features that 1260differ greatly from those of any other class definition module. But 1261Class::Contract does have one significant difference: it allows the 1262class designer to specify "clauses" that implement and enforce a 1263contract on the class's interface. 1264 1265Contract clauses are specified as labelled blocks of code, associated 1266with a particular class, method, or attribute definition. 1267 1268=head2 Class invariants 1269 1270Classes may be given I<invariants>: clauses than must be satisfied at 1271the end of any method call that is invoked from outside the class 1272itself. For example, to specify that a class's object count attribute 1273must never fall below zero: 1274 1275 contract { 1276 invar { ${self->obj_count} >= 0 }; 1277 }; 1278 1279The block following C<invar> is treated as if it were a class method 1280that is automatically invoked after every other method invocation. If the 1281method returns false, C<croak> is invoked with the error message: 1282C<'Class invariant at %s failed'> (where the C<'%s'> is replaced by the file 1283and line number at which the invariant was defined). 1284 1285This error message can be customized, using the C<failmsg> subroutine: 1286 1287 contract { 1288 invar { ${self->obj_count} >= 0 }; 1289 failmsg 'Anti-objects detected by invariant at %s'; 1290 }; 1291 1292Once again, the C<'%s'> is replaced by the appropriate file name and 1293line number. A C<failmsg> can be specified after other types of clause 1294too (see below). 1295 1296A class may have as many invariants as it requires, and 1297they may be specified anywhere throughout the the body of the C<contract>. 1298 1299=head2 Attribute and method pre- and post-conditions 1300 1301Pre- and post-conditions on methods and attributes are specified 1302using the C<pre> and C<post> subroutines respectively. 1303 1304For attributes, pre-conditions are called before the attribute's 1305accessor is invoked, and post-conditions are called after the reference 1306returned by the accessor is no longer accessible. This is 1307achieved by having the accessor return a tied scalar whose C<DESTROY> 1308method invokes the post-condition. 1309 1310Method pre-conditions are tested before their method's implementation is 1311invoked; post-conditions are tested after the implementation finishes 1312(but before the method's result is returned). Constructors are (by 1313definition) class methods and may have pre- and post-conditions, just 1314like any other method. 1315 1316Both types of condition clause receive the same argument list as the 1317accessor or method implementation that they constrain. Both are expected 1318to return a false value if they fail: 1319 1320 contract { 1321 class attr 'obj_count'; 1322 post { ${&value} > 0 }; 1323 failmsg 'Anti-objects detected by %s'; 1324 1325 method 'inc_count'; 1326 post { ${self->obj_count} < 1000000 }; 1327 failmsg 'Too many objects!'; 1328 impl { ${self->obj_count}++ }; 1329 }; 1330 1331Note that within the pre- and post-conditions of an attribute, the 1332special C<value> subroutine returns a reference to the attribute itself, 1333so that conditions can check properties of the attribute they guard. 1334 1335Methods and attributes may have as many distinct pre- and 1336post-conditions as they require, specified in any convenient order. 1337 1338 1339=head2 Checking state changes. 1340 1341Post-conditions and invariants can access the previous state of an object or 1342the class, via the C<old> subroutine. Within any post-condition or invariant, 1343this subroutine returns a reference to a copy of the object or class 1344state, as it was just before the current method or accessor was called. 1345 1346For example, an C<append> method might use C<old> to verify the appropriate 1347change in size of an object: 1348 1349 contract { 1350 method 'append'; 1351 post { @{self->queue} == @{old->queue} + @_ } 1352 impl { push @{self->queue}, @_ }; 1353 }; 1354 1355Note that the implementation's return value is also available in the 1356method's post-condition(s) and the class's invariants, through the 1357subroutine C<value>. In the above example, the implementation of C<append> 1358returns the new size of the queue (i.e. what C<push> returns), so the 1359post-condition could also be written: 1360 1361 contract { 1362 method 'append'; 1363 post { ${&value} == @{old->queue} + @_ } 1364 impl { push @{self->queue}, @_ }; 1365 }; 1366 1367Note that C<value> will return a reference to a scalar or to 1368an array, depending on the context in which the method was originally 1369called. 1370 1371 1372=head2 Clause control 1373 1374Any type of clause may be declared optional: 1375 1376 contract { 1377 optional invar { @{self->list} > 0 }; 1378 failmsg 'Empty queue detected at %s after call'; 1379 }; 1380 1381By default, optional clauses are still checked every time a method or 1382accessor is invoked, but they may also be switched off (and back on) at 1383run-time, using the C<check> method: 1384 1385 local $_ = 'Queue'; # Specify in $_ which class to disable 1386 check my %contract => 0; # Disable optional checks for class Queue 1387 1388This (de)activation is restricted to the scope of the hash that is passed as 1389the first argument to C<check>. In addition, the change only affects the 1390class whose name is held in the variable $_ at the time C<check> is called. 1391This makes it easy to (de)activate checks for a series of classes: 1392 1393 check %contract => 0 for qw(Queue PriorityQueue DEQueue); # Turn off 1394 check %contract => 1 for qw(Stack PriorityStack Heap); # Turn on 1395 1396 1397The special value C<'__ALL__'> may also be used as a (pseudo-)class name: 1398 1399 check %contract => 0 for __ALL__; 1400 1401This enables or disables checking on every class defined using 1402Class::Contract. But note that only clauses that were originally 1403declared C<optional> are affected by calls to C<check>. Non-optional 1404clauses are I<always> checked. 1405 1406Optional clauses are typically universally disabled in production code, 1407so Class::Contract provides a short-cut for this. If the module is 1408imported with the single argument C<'production'>, optional clauses 1409are universally and irrevocably deactivated. In fact, the C<optional> 1410subroutine is replaced by: 1411 1412 sub Class::Contract::optional {} 1413 1414so that optional clauses impose no run-time overhead at all. 1415 1416In production code, contract checking ought to be disabled completely, 1417and the requisite code optimized away. To do that, simply change: 1418 1419 use Class::Contract; 1420 1421to 1422 1423 use Class::Contract::Production; 1424 1425 1426=head2 Inheritance 1427 1428The semantics of class inheritance for Class::Contract classes 1429differ in several respects from those of normal object-oriented Perl. 1430 1431To begin with, classes defined using Class::Contract have a I<static 1432inheritance hierarchy>. The inheritance relationships of contracted classes 1433are defined using the C<inherits> subroutine within the class's C<contract> 1434block: 1435 1436 package PriorityQueue; 1437 contract { 1438 inherits qw( Queue OrderedContainer ); 1439 }; 1440 1441 1442That means that ancestor classes are fixed at compile-time 1443(rather than being determined at run-time by the @ISA array). Note 1444that multiple inheritance is supported. 1445 1446Method implementations are only inherited if they are not explicitly 1447provided. As with normal OO Perl, a method's implementation is inherited 1448from the left-most ancestral class that provides a method of the same name 1449(though with Class::Contract, this is determined at compile-time). 1450 1451Constructors are a special case, however. Their "constructive" 1452behaviour is always specific to the current class, and hence involves 1453no inheritance under any circumstances. However, the "initialising" 1454behaviour specified by a constructor's C<impl> block I<is> inherited. In 1455fact, the implementations of I<all> base class constructors are 1456called automatically by the derived class constructor (in left-most, 1457depth-first order), and passed the same argument list as the invoked 1458constructor. This behaviour is much more like that of other OO 1459programming languages (for example, Eiffel or C++). 1460 1461Methods in a base class can also be declared as being I<abstract>: 1462 1463 contract { 1464 abstract method 'remove'; 1465 post { ${self->count} == ${old->count}-1 }; 1466 }; 1467 1468Abstract methods act like placeholders in an inheritance hierarchy. 1469Specifically, they have no implementation, existing only to reserve 1470the name of a method and to associate pre- and post-conditions with it. 1471 1472An abstract method cannot be directly called (although its associated 1473conditions may be). If such a method is ever invoked, it immediately 1474calls C<croak>. Therefore, the presence of an abstract method in a base 1475class requires the derived class to redefine that method, if the 1476derived class is to be usable. To ensure this, any constructor built by 1477Class::Contract will refuse to create objects belonging to classes with 1478abstract methods. 1479 1480Methods in a base class can also be declared as being I<private>: 1481 1482 contract { 1483 private method 'remove'; 1484 impl { pop @{self->queue} }; 1485 }; 1486 1487Private methods may only be invoked by the class or one of its 1488descendants. 1489 1490=head2 Inheritance and condition checking 1491 1492Attribute accessors and object methods inherit I<all> post-conditions of 1493every ancestral accessor or method of the same name. Objects and classes 1494also inherit all invariants from any ancestor classes. That is, 1495methods accumulate all the post- and invariant checks that their 1496ancestors performed, as well as any new ones they define for themselves, 1497and must satisfy I<all> of them in order to execute successfully. 1498 1499Pre-conditions are handled slightly differently. The principles of 1500design-by-contract programming state that pre-conditions in derived 1501classes can be no stronger than those in base classes (and may well be 1502weaker). In other words, a derived class must handle every case that 1503its base class handled, but may choose to handle other cases as well, 1504by being less demanding regarding its pre-conditions. 1505 1506Meyers suggests an efficient way to achieve this relaxation of 1507constraints without the need for detailed logical analysis of 1508pre-conditions. His solution is to allow a derived class method or 1509accessor to run if I<either> the pre-conditions it inherits are 1510satisfied I<or> its own pre-conditions are satisfied. This is precisely 1511the semantics that Class::Contract uses when checking pre-conditions in 1512derived classes. 1513 1514=head2 A complete example 1515 1516The following code implements a PriorityStack class, in which elements pushed 1517onto the stack "sink" until they encounter an element with lower priority. 1518Note the use of C<old> to check that object state has changed correctly, and 1519the use of explicit dispatch (e.g. C<self-E<gt>Stack::pop>) to invoke 1520inherited methods from the derived-class methods that redefine them. 1521 1522 package PriorityStack; 1523 use Class::Contract; 1524 1525 contract { 1526 # Reuse existing implementation... 1527 inherits 'Stack'; 1528 1529 # Name the constructor (nothing special to do, so no implementation) 1530 ctor 'new'; 1531 1532 method 'push'; 1533 # Check that data to be added is okay... 1534 pre { defined $_[0] }; 1535 failmsg 'Cannot push an undefined value'; 1536 pre { $_[1] > 0 }; 1537 failmsg 'Priority must be greater than zero'; 1538 1539 # Check that push increases stack depth appropriately... 1540 post { self->count == old->count+1 }; 1541 1542 # Check that the right thing was left on top... 1543 post { old->top->{'priority'} <= self->top->{'priority'} }; 1544 1545 # Implementation reuses inherited methods: pop any higher 1546 # priority entries, push the new entry, then re-bury it... 1547 impl { 1548 my ($newval, $priority) = @_[0,1]; 1549 my @betters; 1550 unshift @betters, self->Stack::pop 1551 while self->count 1552 && self->Stack::top->{'priority'} > $priority; 1553 self->Stack::push( {'val'=>$newval, priority=>$priority} ); 1554 self->Stack::push( $_ ) foreach @betters; 1555 }; 1556 1557 method 'pop'; 1558 # Check that pop decreases stack depth appropriately... 1559 post { self->count == old->count-1 }; 1560 1561 # Reuse inherited method... 1562 impl { 1563 return unless self->count; 1564 return self->Stack::pop->{'val'}; 1565 }; 1566 1567 method 'top'; 1568 post { old->count == self->count } 1569 impl { 1570 return unless self->count; 1571 return self->Stack::top->{'val'}; 1572 }; 1573 }; 1574 1575 1576=head1 FUTURE WORK 1577 1578Future work on Class::Contract will concentrate on three areas: 1579 1580=over 4 1581 1582=item 1. Improving the attribute accessor mechanism 1583 1584Lvalue subroutines will be introduced in perl version 5.6. They will allow 1585a return value to be treated as an alias for the (scalar) argument of a 1586C<return> statement. This will make it possible to write subroutines whose 1587return value may be assigned to (like the built-in C<pos> and C<substr> 1588functions). 1589 1590In the absence of this feature, Class::Contract accessors of all types 1591return a reference to their attribute, which then requires an explicit 1592dereference: 1593 1594 ${self->value} = $newval; 1595 ${self->access_count}++; 1596 1597When this feature is available, accessors for scalar attributes will be 1598able to return the actual attribute itself as an lvalue. The above code 1599would then become cleaner: 1600 1601 self->value = $newval; 1602 self->access_count++; 1603 1604 1605=item 2. Providing better software engineering tools. 1606 1607Contracts make the consequences of inheritance harder to predict, since 1608they significantly increase the amount of ancestral behaviour (i.e. 1609contract clauses) that a class inherits. 1610 1611Languages such as Eiffel provide useful tools to help the 1612software engineer make sense of this extra information. In 1613particular, Eiffel provides two alternate ways of inspecting a 1614particular class -- flat form and short form. 1615 1616"Flattening" a class produces an equivalent class definition without any 1617inheritance. That is, the class is modified by making explicit all the 1618attributes, methods, conditions, and invariants it inherits from other 1619classes. This allows the designer to see every feature a class possesses 1620in one location. 1621 1622"Shortening" a class, takes the existing class definition and removes all 1623implementation aspects of it -- that is, those that have no bearing on its 1624public interface. A shortened representation of a class therefore has all 1625attribute specifications and method implementations removed. Note that 1626the two processes can be concatenated: shortening a flattened class 1627produces an explicit listing of its complete public interface. Such a 1628representation can be profitably used as a basis for documenting the 1629class. 1630 1631It is envisaged that Class::Contract will eventually provide a mechanism to 1632produce equivalent class representations in Perl. 1633 1634 1635=item 3. Offering better facilities for retrofitting contracts. 1636 1637At present, adding contractual clauses to an existing class requires a 1638major restructuring of the original code. Clearly, if design-by-contract 1639is to gain popularity with Perl programmers, this transition cost must 1640be minimized. 1641 1642It is as yet unclear how this might be accomplished, but one possibility 1643would be to allow the implementation of certain parts of a 1644Class::Contract class (perhaps even the underlying object implementation 1645itself) to be user-defined. 1646 1647=back 1648 1649=head1 AUTHOR 1650 1651Damian Conway (damian@conway.org) 1652 1653=head1 MAINTAINER 1654 1655C. Garrett Goebel (ggoebel@cpan.org) 1656 1657=head1 BUGS 1658 1659There are undoubtedly serious bugs lurking somewhere in code this funky :-) 1660Bug reports and other feedback are most welcome. 1661 1662=head1 COPYRIGHT 1663 1664Copyright (c) 1997-2000, Damian Conway. All Rights Reserved. 1665This module is free software. It may be used, redistributed 1666and/or modified under the terms of the Perl Artistic License 1667 (see http://www.perl.com/perl/misc/Artistic.html) 1668 1669Copyright (c) 2000-2001, C. Garrett Goebel. All Rights Reserved. 1670This module is free software. It may be used, redistributed 1671and/or modified under the terms of the Perl Artistic License 1672 (see http://www.perl.com/perl/misc/Artistic.html) 1673