May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #32 from Stewart Gordon <smjg@iname.com> 2012-05-04 10:38:33 PDT ---
(In reply to comment #30)
> fizzbuzz() clearly has a bug. It will fail if given an A which isn't actually a
> B.

Exactly.  fizzbuzz is calling a method of A, not a method of B.  As such, as I've already said, it must conform to A's API, but it is failing to do so.

(In reply to comment #31)
> I understand the distinction, and how the slides doesn't make it clear that the precondition is dynamically bound. In fact the author found it so obvious as to be unnecessary to mention

So it could have been just an oversight for all we know.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #33 from Walter Bright <bugzilla@digitalmars.com> 2012-05-04 11:42:40 PDT ---
(In reply to comment #32)
> (In reply to comment #30)
> > fizzbuzz() clearly has a bug. It will fail if given an A which isn't actually a
> > B.
> 
> Exactly.  fizzbuzz is calling a method of A, not a method of B.  As such, as I've already said, it must conform to A's API, but it is failing to do so.

First off, if fizzbuzz() is passed an A, then it will (correctly) fail. Where's
the bug in the contract design? Secondly, the -1 may not be a literal, it may
be a value computed from B, as in:


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

So, clearly is NOT required that a.foo(arg) pass A.foo's contract.

The design of OOP and contracts is sound. Correct programs will pass, and incorrect programs will fail. I don't see any "corner cases" otherwise.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #34 from Stewart Gordon <smjg@iname.com> 2012-05-04 13:27:50 PDT ---
(In reply to comment #33)
OK, so there's this issue.  It may also be a documented guarantee that the
return value from bar is a valid argument for foo.

But you could still argue that the call is in breach of A's API and therefore the code is incorrect.  To be correct, the in contract for A.foo would have to be something like

in { assert(x > 0 || x == bar()); }

But since enforcing this now is a potentially breaking change, I can now see a case for leaving the behvaiour as it is.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #35 from Walter Bright <bugzilla@digitalmars.com> 2012-05-04 13:41:50 PDT ---
(In reply to comment #34)
> But you could still argue that the call is in breach of A's API and therefore the code is incorrect.

Again, this is NOT true. The type of the argument is not statically A, it is a polymorphic type A.

If an instance of A is passed, then the call to foo(-1) will fail. Please try it and see for yourself. There is no hole in the system.


> To be correct, the in contract for A.foo would have to
> be something like
> 
> in { assert(x > 0 || x == bar()); }
> 
> But since enforcing this now is a potentially breaking change, I can now see a case for leaving the behvaiour as it is.

You are still seeing this as a bug in the OOP design. It is not. The design is sound and correct.

If you still disagree, please write a code sample that asserts when it should not, or passes when it must not, compile it and run it, and post it here.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #36 from Stewart Gordon <smjg@iname.com> 2012-05-04 13:49:11 PDT ---
(In reply to comment #35)
<snip>
> Again, this is NOT true. The type of the argument is not statically A, it is a polymorphic type A.

Why do you consider the contracts of a method to be NOT part of the API? Because Bertrand considers it so, or for some other reason?

> If an instance of A is passed, then the call to foo(-1) will fail. Please try it and see for yourself.

I never doubted that.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #37 from Walter Bright <bugzilla@digitalmars.com> 2012-05-04 14:13:50 PDT ---
(In reply to comment #36)
> (In reply to comment #35)
> <snip>
> > Again, this is NOT true. The type of the argument is not statically A, it is a polymorphic type A.
> 
> Why do you consider the contracts of a method to be NOT part of the API?

This is not what I am considering. I am saying that A is a polymorphic type, not a static type. The contracts that apply depend on the runtime polymorphic type, not the static type.


> Because Bertrand considers it so, or for some other reason?

I am not using argument by authority. Meyer explains it quite well, step by step, in his book I recommended to you. The behavior is an inevitable consequence of the fundamental principles of OOP. That is why it is not a matter of opinion.


> > If an instance of A is passed, then the call to foo(-1) will fail. Please try it and see for yourself.
> 
> I never doubted that.

Then I am lost as to what you think is broken in the design.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #38 from Stewart Gordon <smjg@iname.com> 2012-05-04 14:30:40 PDT ---
(In reply to comment #37)
> Then I am lost as to what you think is broken in the design.

In how many different ways does the same thing need to be explained to you before you understand it?

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.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #39 from Walter Bright <bugzilla@digitalmars.com> 2012-05-04 14:46:11 PDT ---
Please write a piece of code that asserts when it should not, or passes when it should not, compile it, verify this incorrect behavior, and post it here.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #40 from Stewart Gordon <smjg@iname.com> 2012-05-04 14:52:44 PDT ---
(In reply to comment #39)
> Please write a piece of code that asserts when it should not, or passes when it should not, compile it, verify this incorrect behavior, and post it here.

Timon has already done this and posted it in the description when filing this report in the first place.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 04, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #41 from Walter Bright <bugzilla@digitalmars.com> 2012-05-04 15:18:08 PDT ---
(In reply to comment #40)
> (In reply to comment #39)
> > Please write a piece of code that asserts when it should not, or passes when it should not, compile it, verify this incorrect behavior, and post it here.
> 
> Timon has already done this and posted it in the description when filing this report in the first place.

Example #1 expects behavior based on the static type, which is not polymorphic OOP at all. Of course x.foo() should check B's widened interface, because:

    x is a B!

The example's rationale is completely invalid.

Please read Meyer's book.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------