digitalmars.D.learn - The interface's 'in' contract passes if it makes a virtual function
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (48/48) Nov 04 2014 Perhaps I am expecting too much from the current 'in' contract design
- bearophile (4/6) Nov 04 2014 The "in contract" is named pre-condition, or precondition.
- Steven Schveighoffer (10/58) Nov 04 2014 This looks like a dmd bug. My theory is that the call to virtualCheck is...
- Steven Schveighoffer (53/123) Nov 04 2014 Yep. I debugged it. It's calling toHash instead.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (28/29) Nov 04 2014 Yeah, you were spot on. :) I did a different experiment. I added a
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (4/5) Nov 04 2014 Posted:
Perhaps I am expecting too much from the current 'in' contract design and implementation. ;) Still, the virtual function call in the following interface's 'in' contract should be dispatched to the implementaion in the derived class, right? It seems like mere presence of that virtual function call causes the 'in' contract of the interface succeed and the derived's 'in' contract never gets called. import std.stdio; void main() { /* EXPECTATION: The following call should execute both the * base's and the derived's in contracts 50% of the time * because the base's contract fails randomly. */ (new C()).foo(); } interface I { void foo() in { writeln("I.foo.in"); /* This check succeeds without calling virtualCheck! */ assert(virtualCheck()); } bool virtualCheck(); } class C : I { void foo() in { writeln("C.foo.in"); } body {} bool virtualCheck() { writeln("C.virtualCheck"); /* Fail randomly 50% of the time */ import std.random; import std.conv; return uniform(0, 2).to!bool; } } The output has no mention of C.virtualCheck nor C.foo.in: I.foo.in <-- Where is C.virtualCheck? <-- Where is C.foo.in? Ali
Nov 04 2014
Ali Çehreli:Perhaps I am expecting too much from the current 'in' contract design and implementation. ;)The "in contract" is named pre-condition, or precondition. Bye, bearophile
Nov 04 2014
On 11/4/14 3:01 PM, Ali Çehreli wrote:Perhaps I am expecting too much from the current 'in' contract design and implementation. ;) Still, the virtual function call in the following interface's 'in' contract should be dispatched to the implementaion in the derived class, right? It seems like mere presence of that virtual function call causes the 'in' contract of the interface succeed and the derived's 'in' contract never gets called. import std.stdio; void main() { /* EXPECTATION: The following call should execute both the * base's and the derived's in contracts 50% of the time * because the base's contract fails randomly. */ (new C()).foo(); } interface I { void foo() in { writeln("I.foo.in"); /* This check succeeds without calling virtualCheck! */ assert(virtualCheck()); } bool virtualCheck(); } class C : I { void foo() in { writeln("C.foo.in"); } body {} bool virtualCheck() { writeln("C.virtualCheck"); /* Fail randomly 50% of the time */ import std.random; import std.conv; return uniform(0, 2).to!bool; } } The output has no mention of C.virtualCheck nor C.foo.in: I.foo.in <-- Where is C.virtualCheck? <-- Where is C.foo.in? AliThis looks like a dmd bug. My theory is that the call to virtualCheck is going to the WRONG vtbl address. I have seen stuff like this before. It likely is calling something like toString. You would have to debug to figure it out. So what I think happens is it calls the wrong virtual function, which returns non-zero always, and obviously doesn't print anything, and then continues on. I added a writeln("after virtual check") to the in contract of I.foo, and it writes that too. -Steve
Nov 04 2014
On 11/4/14 3:26 PM, Steven Schveighoffer wrote:On 11/4/14 3:01 PM, Ali Çehreli wrote:Yep. I debugged it. It's calling toHash instead. Proof (the weird casting thing is because I wanted to call writeln from toHash, but toHash is nothrow and writeln is not) : import std.stdio; void main() { /* EXPECTATION: The following call should execute both the * * base's and the derived's in contracts 50% of the time * * because the base's contract fails randomly. */ (new C()).foo(); } interface I { void foo() in { writeln("I.foo.in"); /* This check succeeds without calling virtualCheck! */ assert(this.virtualCheck()); writeln("after virtual check"); } bool virtualCheck(); } void printToHash() { writeln("in toHash");} class C : I { void foo() in { writeln("C.foo.in"); } body {} bool virtualCheck() { writeln("C.virtualCheck"); /* Fail randomly 50% of the time */ import std.random; import std.conv; return uniform(0, 2).to!bool; } override size_t toHash() trusted { auto f = cast(void function() nothrow)&printToHash; f(); return 1; } } output: I.foo.in in toHash after virtual check Please report to bugzilla. -StevePerhaps I am expecting too much from the current 'in' contract design and implementation. ;) Still, the virtual function call in the following interface's 'in' contract should be dispatched to the implementaion in the derived class, right? It seems like mere presence of that virtual function call causes the 'in' contract of the interface succeed and the derived's 'in' contract never gets called. import std.stdio; void main() { /* EXPECTATION: The following call should execute both the * base's and the derived's in contracts 50% of the time * because the base's contract fails randomly. */ (new C()).foo(); } interface I { void foo() in { writeln("I.foo.in"); /* This check succeeds without calling virtualCheck! */ assert(virtualCheck()); } bool virtualCheck(); } class C : I { void foo() in { writeln("C.foo.in"); } body {} bool virtualCheck() { writeln("C.virtualCheck"); /* Fail randomly 50% of the time */ import std.random; import std.conv; return uniform(0, 2).to!bool; } } The output has no mention of C.virtualCheck nor C.foo.in: I.foo.in <-- Where is C.virtualCheck? <-- Where is C.foo.in? AliThis looks like a dmd bug. My theory is that the call to virtualCheck is going to the WRONG vtbl address. I have seen stuff like this before. It likely is calling something like toString. You would have to debug to figure it out. So what I think happens is it calls the wrong virtual function, which returns non-zero always, and obviously doesn't print anything, and then continues on. I added a writeln("after virtual check") to the in contract of I.foo, and it writes that too.
Nov 04 2014
On 11/04/2014 12:41 PM, Steven Schveighoffer wrote:Yep. I debugged it. It's calling toHash instead.Yeah, you were spot on. :) I did a different experiment. I added a number of functions to the interface (before virtualCheck()) and implementations to the class: interface I { // ... bool a(); bool b(); bool c(); bool d(); bool virtualCheck(); } class C : I { // ... bool a() { return false; } bool b() { return false; } bool c() { return false; } bool d() { return false; } } Adding only a() calls C's precondition unconditionally (because it pushes virtualCheck() to the next slot in vtbl.) Adding a() and b() has the same effect. Adding a(), b(), and c() prints I.foo.in indefinitely. :) Finally, adding a(), b(), c(), and d() seems to bring the expected behavior. :) Ali
Nov 04 2014
On 11/04/2014 12:26 PM, Steven Schveighoffer wrote:This looks like a dmd bug.Posted: https://issues.dlang.org/show_bug.cgi?id=13687 Ali
Nov 04 2014