p0nce / d-idioms

"Effective D" without the haircut.
http://p0nce.github.io/d-idioms/
82 stars 17 forks source link

The D object model #137

Closed p0nce closed 6 years ago

p0nce commented 6 years ago

Explain how interface work, because I don't know it for real "druntime/src/rt/cast_.d" advice from ketmar

p0nce commented 6 years ago
import std.stdio;

interface I
{
    void lol();
}

interface J
{
    void more_lol();
}

class B : I
{
    void lol()
    {
    }
}

// Diamond to the two interfaces, one inherits to the other
class A : B, J
{
    override void lol()
    {
    }

    void more_lol()
    {
    }
}

// Diamond to the same interface
class A2 : B, I
{
    override void lol()
    {
    }

    void more_lol()
    {
    }
}

// Normal case, no diamond
class A3 : B
{
    override void lol()
    {
    }

    void more_lol()
    {
    }
}

void displayOffset(Class, Interface)()
{
    Class obj= new Class;
    void* instance = cast(void*)obj;
    void* inter = cast(void*)(cast(Interface)obj );
    writeln("  Offset of the ", Interface.stringof, " slot in ", Class.stringof, " is ", inter - instance, " bytes.");
}

void main()
{
    writeln("A diamond A->B, A->J->I and B->I   => instance is ", __traits(classInstanceSize, A), " bytes");
    displayOffset!(A, I);          
    displayOffset!(A, J);
    displayOffset!(B, I);    
    writeln;

    writeln("A diamond A2->B, A2->I and B->I    => instance is ", __traits(classInstanceSize, A2), " bytes");
    displayOffset!(A2, I);          
    displayOffset!(B, I);
    writeln;

    writeln("No diamond, A3->B->I               => instance is ", __traits(classInstanceSize, A3), " bytes");
    displayOffset!(A3, I);          
    displayOffset!(B, I); 
    writeln;
}

Results:

<p0nce> A diamond A->B, A->J->I and B->I   => instance is 16 bytes
<p0nce>   Offset of the I slot in A is 8 bytes.
<p0nce>   Offset of the J slot in A is 12 bytes.
<p0nce>   Offset of the I slot in B is 8 bytes.
<p0nce> A diamond A2->B and B->I           => instance is 16 bytes
<p0nce>   Offset of the I slot in A2 is 12 bytes.
<p0nce>   Offset of the I slot in B is 8 bytes.
<p0nce> No diamond, A3->B->I               => instance is 12 bytes
<p0nce>   Offset of the I slot in A3 is 8 bytes.
<p0nce>   Offset of the I slot in B is 8 bytes.
<p0nce> tl;dr interface slots are exactly like fields. At the point where you inherit the interface, it adds a new slot to your object at the end, even if it's an interface that could be found in the parent hierarchy
<p0nce> read "A diamond A2->B, A2->I and B->I" instead of "A diamond A2->B and B->I" 
p0nce commented 6 years ago

beautifully explained by feep https://feepingcreature.github.io/oop.html