Static versus dynamic binding of in contracts again - trying to set things straight

2012-05-05 Thread Stewart Gordon

http://d.puremagic.com/issues/show_bug.cgi?id=6857

It seems we can't all be agreed on how it should be.


It seems part of the problem is that there are two views on the essence of an in contract 
in an OOP context:


(a) it is part of the API of the class and, as such, a specification to which any user of 
the class must conform


(b) it is a means of verifying that the target object can handle the input being passed 
into it


Current D takes view (b), by checking the in contract according to the actual class of the 
object - dynamic binding.  Several of us (myself included) have argued on the basis of 
view (a), that it should be checked according to the compile-time type of the object 
reference - static binding.



So far, there have been arguments both ways.

Arguments in favour of static binding:

s1. A user of a class A, in the general case, doesn't know whether something of type A is 
a plain A or something of some subclass of A.  This is part of the OO principle of 
encapsulation.  As such, it doesn't make sense for the class user to rely on the widened 
preconditions in subclasses it doesn't know about.  (But see d3.)


s2. As such, it helps detect more bugs in code that uses a class of which programmers are 
likely to create subclasses.


s3. Obeys the Liskov substitution principle.

s4. Consistency with the inability of a base class user to call methods that exist only in 
a derived class.  If a subclass introduces a new method, that new method doesn't exist 
from the base class's point of view.  In the same way, if a subclass introduces new legal 
arguments to a method, those new legal arguments don't exist from the base class's point 
of view.



Arguments in favour of dynamic binding:

d1. It's part of how overriding is meant to work, per OO principles.  A method call is 
resolved through the virtual method table of the object's actual class.  (But this is 
based on the premise that an in contract is just another method.  Which it isn't.  An in 
contract is a specification of what is a legal call of a method, quite a different concept 
from the method itself, which provides functionality to the class.)


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.)


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());
}

(While I can see this being useful, it doesn't change the fact that fizzbuzz is asking the 
class A, not the class B, for the method foo.  And the A.foo contract could just as well 
have been written

in { assert(x > 0 || x == bar()); }
thereby causing the call to conform according to view (a) above, hence (d4 aside) enabling 
static binding to be considered without this getting in the way.)


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.)



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.


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.


If (a), then we need static binding.  But how do we deal with the code breakage pointed 
out in d4?


If (b), then we need to stick with the current dynamic binding.  And people taking view 
(a) will still complain about it.  But a clear spec on the issue would at least be 
something to which people complaining about (a) can be pointed.


Stewart.


Re: Static versus dynamic binding of in contracts again - trying to set things straight

2012-05-05 Thread deadalnix

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.


Re: Static versus dynamic binding of in contracts again - trying to set things straight

2012-05-05 Thread Stewart Gordon

On 05/05/2012 15:07, deadalnix wrote:


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.


Exactly.  Moreover, I noticed that you quoted portions of it on BZ, including
"Yet, because of dynamic binding, A may subcontract the execution of r to B, and it is B’s 
contract that will be applied."


There seems to be an unfounded assumption here: that a compiler will necessarily implement 
contract checking as part of the method body.  Really, there's no explanation of "it is 
B’s contract that will be applied" there.  Contract checking happens before and is 
conceptually separate from method execution.



Additionally, Meyer state that the in contract is a constraint for
the caller.  This is an argument in favor of view (a).


That is indeed what it seems to be saying.  Among other things:
"A precondition violation indicates a bug in the client (caller). The caller did not 
observe the conditions imposed on correct calls."




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.


Taken the words out of my mouth there.  fizzbuzz is not using the class B.  It is using 
the class A.  Going by view (a), since foo(-1) is not a legal call according to A's API - 
and moreover, A's API makes no guarantees that foo(bar()) generally will be a legal call - 
the code is incorrect.


I agree with the rest of your points as well.



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.



Where is it addressed?

Stewart.


Re: Static versus dynamic binding of in contracts again - trying to set things straight

2012-05-09 Thread Regan Heath
Reading that summary, and deadalnix's further comment I am inclined to  
agree that contracts should be (a) static.


It also made me think.. are we defining in/out contracts in the wrong  
place?  or in the wrong way?  What if we defined them on interfaces  
instead of classes?  After all, interfaces are the other form of contracts  
that we use in OOP and it would make sense to me that an in/out contract  
defined on an interface would be static, and would not change dynamically  
with sub-classes etc.


Perhaps we could have both static and dynamic contracts?  Contracts  
defined on classes (not interfaces) could remain dynamic as they are  
currently, but contracts defined on interfaces could be static.  Giving us  
the best of both worlds.


Regan

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Static versus dynamic binding of in contracts again - trying to set things straight

2012-05-09 Thread Stewart Gordon

On 09/05/2012 11:55, Regan Heath wrote:

Reading that summary, and deadalnix's further comment I am inclined to agree 
that
contracts should be (a) static.

It also made me think.. are we defining in/out contracts in the wrong place? or 
in the
wrong way? What if we defined them on interfaces instead of classes?


We should be able to define contracts on interface methods, abstract class methods and 
normal class methods on an equal footing.


http://d.puremagic.com/issues/show_bug.cgi?id=6549



Perhaps we could have both static and dynamic contracts? Contracts defined on 
classes (not
interfaces) could remain dynamic as they are currently, but contracts defined on
interfaces could be static. Giving us the best of both worlds.


I'm not sure what the point of this would be.  What is the best of the dynamic 
contract world?

Moreover, classes define an API in the same way as interfaces do.  Violating a contract on 
a class method is violating the API in the same way as it is for interfaces.  It would be 
arbitrary and confusing to have this conjured-up difference between classes and interfaces.


Stewart.


Re: Static versus dynamic binding of in contracts again - trying to set things straight

2012-05-09 Thread Regan Heath
On Wed, 09 May 2012 13:23:03 +0100, Stewart Gordon   
wrote:



On 09/05/2012 11:55, Regan Heath wrote:
Reading that summary, and deadalnix's further comment I am inclined to  
agree that

contracts should be (a) static.

It also made me think.. are we defining in/out contracts in the wrong  
place? or in the

wrong way? What if we defined them on interfaces instead of classes?


We should be able to define contracts on interface methods, abstract  
class methods and normal class methods on an equal footing.


http://d.puremagic.com/issues/show_bug.cgi?id=6549


Perhaps we could have both static and dynamic contracts? Contracts  
defined on classes (not
interfaces) could remain dynamic as they are currently, but contracts  
defined on

interfaces could be static. Giving us the best of both worlds.


I'm not sure what the point of this would be.  What is the best of the  
dynamic contract world?


I've only read the summary, so... If there is no consensus then someone  
obviously sees some benefit to it.  Personally, as I said, I think  
"static" is the 'correct' way for contracts to work, but perhaps the  
reason why ppl like dynamic is that 'correct' is not always 'practical' or  
'useful'.  Having dynamic contracts allows sub-classes to alter them, that  
could be a benefit to some.  It doesn't seem 'correct' to me, violating  
the substitution principle and all, but I can see how it might be  
practical/useful.



Moreover, classes define an API in the same way as interfaces do.


Yes, but an API is only one part or one form of contract.  in/out  
contracts provide additional limitations/guarantees, beyond what a  
"standard"(*) OOP API does.  For example, a "standard"(*) OOP API can only  
define the type of input, not the range of acceptable values.


(*) I'm saying "standard" here because I'm referring to the common usage  
of class, sub-class, interface without the addition of more complex  
template, static if, mixin, or other language features not common to the  
main OOP languages; C++, Java, C#, ..


Violating a contract on a class method is violating the API in the same  
way as it is for interfaces.  It would be arbitrary and confusing to  
have this conjured-up difference between classes and interfaces.


I agree, classes and interfaces define APIs.  But, an interface is  
generally thought of as a more formal API, somehow /more/ of a contract  
than whatever methods happen to exist in a class at a given time.  in/out  
are currently used as an additional contracts, and currently applied to  
class methods.  But, is that 'correct'?


It seemed to me it might be cleaner/clearer and more correct to require  
in/out to be applied only to interfaces, where there is no concrete  
implementation.  Having applied them to classes and moreover to specific  
implementations of methods in classes we've created the idea that they  
could be dynamic and I suspect the current dynamic implementation in DMD  
just followed naturally from that.


I agree, having different behaviour for interfaces/classes /might/ be  
confusing.. Then again, I would expect static behaviour from an in/out  
defined on an interface, and it seems that some people expect dynamic  
behaviour from in/out defined on classes so it's possible that it's just  
the behaviour people would expect.  In any case I only suggested it as a  
possible middle ground.


Personally I'd like to explore the idea that it might be less confusing  
and more correct to require the use of an interface to define in/out  
contracts.  Would that be too much of a burden?  Would it result in a huge  
number of "redundant" interfaces?  Or, would it force people to write more  
correct code?  I know I've see /a lot/ of code which would have been  
written better had someone had the forethought to design the  
interfaces/contracts first, and once they exist would have thought harder  
about changing them during initial development and beyond.


Regan

--
Using Opera's revolutionary email client: http://www.opera.com/mail/