The interface's 'in' contract passes if it makes a virtual function call
    Steven Schveighoffer via Digitalmars-d-learn 
    digitalmars-d-learn at puremagic.com
       
    Tue Nov  4 12:41:39 PST 2014
    
    
  
On 11/4/14 3:26 PM, Steven Schveighoffer wrote:
> 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?
>>
>> Ali
>
> This 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.
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.
-Steve
    
    
More information about the Digitalmars-d-learn
mailing list