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