On 03/11/2012 03:21 AM, Damian Conway wrote: > 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.
And here the problem already starts. Signatures with where-blocks can't by compared by a Turing machine. At least we know which signatures we can compare and which we can't. So we need to think about that case too. > 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. +1 Though of course then we need a mechanism to silence that warning. > 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. ;-) I think we reserve all-caps names anyway, though I can't find the reference to it right now. > > 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; > } > } Just a small syntax nit: I think your example of 'will require BLOCK' is a violation of the rule that we shouldn't have two terms in a row. Probably better to go with 'requires' and 'ensures' traits right away: method foo(Num $x --> Num $result) requires { $x < 10 } ensures { $result > $x } { return 2 * $x; } > 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). Or we simply reuse the convention from POST and CATCH that the interesting value (either exception or return value) is passed in as $_.