Carl asked: > class A { > method foo($x) { > PRE { $x < 10 } > # ... > } > } > > class B is A { > method foo($a, $b, $c) { > PRE { [>] $a, $b, $c } > # ... > } > } > > When C<B.foo> is called, are both C<PRE> blocks meant to be run?
No. Contractual constraints are only inherited by methods of the same signature. BTW, that example isn't Liskov substitutable, so it really doesn't matter what it does under DbC. ;-) Also, it would be much better if such cases issued a warning in Perl 6, rather than just silently hiding the inherited method and thereby breaking the shared polymorphic interface of the hierarchy. > A modest proposal: we already have excellent IoC primitives with > C<nextsame> et al. Why not let DBC fall out of their use instead of > trying to impose it from the outside? This poses no problems at all: Except for the problem that it doesn't actually implement DbC semantics. ;-) For example: class A { method foo($x) { PRE { $x < 10 } my $result = 2 * $x; return $result; POST { $result > $x } } } class B is A { method foo($x) { PRE { $x < 100 } callwith($c % 10); return -$c; } } In a proper DbC system, calling B::foo would always fail, since A::foo's inherited POST requires the method's result be greater than its original argument. But under the proposed new semantics, this example succeeds in returning a result that violates the inherited contract. Even worse, this example: class A { method foo($x) { PRE { $x < 10 } my $result = 2 * $x; return $result; POST { $result > $x } } } class B is A { method foo($x) { PRE { $x < 100 } return -$c; } } ...fails to even test the inherited PRE and POST conditions, which is a complete violation of DbC. Note that I'm *not* saying that Carl's example isn't demonstrating useful behaviour...just that the behaviour it's demonstrating isn't DbC. For a start, PRE- and POST- inheritance should only occur when a derived method does indeed have the same signature as some base method, and then only from that identically signatured method. Secondly, PREs have to be inherited disjunctively (i.e. be allowed to weaken), rather than being conjunctively accumulated (i.e. being forced to to strengthened). > In fact, method-level C<PRE> and C<POST> cease to be a concept, C<PRE> > and C<POST> submethods can be handled delicately in a corner of the > MOP somewhere, the abomination that is C<CALL-VIA-DBC> goes away, and > all that we're really left with are block-level C<PRE> and C<POST> > phasers, which already seem like they could work. > > So, what do y'all think? I think this is probably the only reasonable way forward at the moment. What we've proposed as a DbC mechanism in the spec can't be implemented for all the reasons Carl enumerated so well. However, I'd also want the spec to remove all reference to DbC when talking about PRE and POST. Or, better still, to state explicitly that PRE and POST do *not* have DbC semantics when applied to methods (perhaps even using some of the examples above to illustrate why not). And if we are ever to properly supply DbC, then I think we'd also want to explicitly reserve--but not spec--the phaser names REQUIRE and ENSURE for possible later use (either in-core or via a future 'use contracts' pragma or module that some heroic soul may attempt write. ;-) On the other hand, because DbC "requires" and "ensures" are really much more like (inheritable) traits of a method's signature, rather than phasers tied to the method's block, it seems likely that any eventual DbC mechanism should not use phasers at all. So perhaps we ought to reserve the traits 'will require' and 'will ensure' so that the eventual DbC mechanism could be specified like so: class A { method foo(Num $x --> Num $result) will require { $x < 10 } will ensure { $result > $x } { return 2 * $x; } } class B is A { method foo(Num $x --> Num) will require { $x < 100 } { return $x+1; } } And, yes, this does indeed imply a syntax for optionally naming the return value in a signature (which syntax seems to fall out quite naturally in any case). Damian