Static versus dynamic binding of in contracts again - trying to set things straight
deadalnix
deadalnix at gmail.com
Sat May 5 07:07:24 PDT 2012
Le 05/05/2012 14:46, Stewart Gordon a écrit :
> d2. Bertrand Meyer's book explains why this is the way in which it must
> work. (But the truth of this claim has been challenged.)
>
http://se.ethz.ch/~meyer/publications/computer/contract.pdf
The extract of the book covering that specific point is available here.
Meyer explain HOW thing work and then how this behavior provide some
benefices. Careful reading of the passage show that BOTH behavior we are
talking here provide such benefices. This reading isn't going to
conclude the discussion.
Additionally, Meyer state that the in contract is a constraint for the
caller. This is an argument in favor of view (a).
I do think EIFFEL implementation provide less benefices than the
proposed new behavior.
I plan to contact Meyer himself to discuss the subject.
> d3. It allows inputs not allowed by the base class contract to be passed
> in under controlled conditions - conditions in which some other method
> is defined from whose return value the legality of some input can be
> determined. Example provided by Walter himself:
>
> class A {
> void foo(int x) in { assert(x > 0); } body {}
> int bar() { return 1; }
> }
>
> class B : A {
> void foo(int x) in { assert(x > -2); } body {}
> int bar() { return -1; }
> }
>
> void fizzbuzz(A a) {
> a.foo(bar());
> }
>
The fizzbuzz function here is flawed. bar doesn't provide any guarantee
on its return value. foo expect fizzbuzz to provide a parameter with
certain properties.
fizzbuzz is unable to ensure it is doing its part of the contract.
Correct alternative are either :
- adding an out contract on A.bar to ensure that the value returned is
above 0 and so can be safely passed to foo. This solution make B.bar
invalid, but fizzbuzz now is able to honor its part f the contract.
- adding a new condition to A.foo's in contract to accept bar's return
value. This also require that A.bar is made pure.
- fizzbuzz is rewritten to ensure that the value returned by bar is
valid according to foo's contract. The only contract that fizzbuzz knows
about is A.foo and so it should apply criteria on that one. It means
that B.bar's return valus will be discarded by fizzbuzz and it will not
call a.foo in case of a being an instance of B.
> d4. Now that D behaves in this way, there is going to be code out there
> that does something like the example in d3. Changing to static binding
> would break this code. (This seems the one argument for dynamic binding
> that I'm inclined to agree with.)
>
As seen above, cases where things risk to break is exactly what we want.
Contract is supposed to break bad code ASAP.
> deadalnix has pointed out that design of OOP doesn't say anything about
> contracts. In which case any claim that the whole OOP paradigm takes
> either view (a) or view (b) is nonsense.
>
After some thinking, I want to make a stronger point.
A good guideline in OOP is to hide implementation. A contract is an
agreement between the caller and the callee, and so, mustn't be hidden
in any way. It certainly exclude the contract as being part of the
implementation.
view (b) imply that the in contract is part of the implementation (ie,
can the provided implementation handle that input or not). OOP don't say
anything about contracts, but view (b) is breaking encapsulation, and
encapsulation is an OOP principle.
> Maybe what's needed is a clarification in the spec of which concept of
> an in contract (view (a), view (b) or something else) D intends to
> implement.
>
The spec is very explicit on that point. view (b) is the specified one.
But I think it is an error.
> If (a), then we need static binding. But how do we deal with the code
> breakage pointed out in d4?
>
Breaking flawed code is a benefit, not an issue.
More information about the Digitalmars-d
mailing list