September 10, 2017
On Sunday, 10 September 2017 at 14:04:20 UTC, rikki cattermole wrote:
> On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
>> If TypeInfo for extern(C++) classes is removed, couldn't final extern(C++) classes without base class and which don't implement any interfaces omit the vtable so that the following assert holds:
>> 
>> ---
>> final extern(C++) class Foo {}
>> static assert (__traits(classInstanceSize, Foo) == 0LU);
>> ---
>> 
>> The reason I ask is that fairly often I have an abstraction that's better suited as a reference type than a value type, but doesn't need any runtime polymorphy (or the monitor standard classes have). Structs + pointers are the only way I know of to avoid the (in this special case) unneeded vtable overhead, but it always ends up looking worse to read.
>
> We can do it for any class if its final.

Even final classes can always inherit (potentially already overridden) virtual methods from their parent classes and since all normal D classes inherit from core.object : Object [1], which defines virtual methods (`toString`, `toHash`, `opCmp, and `opEquals`), I don't see how this can be true.

> The problem isn't generating the vtable's. But the information required for casting.

This applies to normal D classes, but D doesn't support (dynamic) casts for extern(C++) classes, anyway, so this shouldn't be an issue for them.

[1] https://github.com/somzzz/druntime/blob/74882c8a48dd8a827181e3b89c4f0f205c881ac5/src/object.d#L50
September 10, 2017
By the way, can we dynamic_cast extern(C++) classes in C++? If not, what are we generating these TypeInfo_Class for?
September 10, 2017
On Sunday, 10 September 2017 at 14:42:42 UTC, Moritz Maxeiner wrote:
> On Sunday, 10 September 2017 at 14:04:20 UTC, rikki cattermole wrote:
>> On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
>>> If TypeInfo for extern(C++) classes is removed, couldn't final extern(C++) classes without base class and which don't implement any interfaces omit the vtable so that the following assert holds:
>>> 
>>> ---
>>> final extern(C++) class Foo {}
>>> static assert (__traits(classInstanceSize, Foo) == 0LU);
>>> ---
>>> 
>>> The reason I ask is that fairly often I have an abstraction that's better suited as a reference type than a value type, but doesn't need any runtime polymorphy (or the monitor standard classes have). Structs + pointers are the only way I know of to avoid the (in this special case) unneeded vtable overhead, but it always ends up looking worse to read.
>>
>> We can do it for any class if its final.
>
> Even final classes can always inherit (potentially already overridden) virtual methods from their parent classes and since all normal D classes inherit from core.object : Object [1], which defines virtual methods (`toString`, `toHash`, `opCmp, and `opEquals`), I don't see how this can be true.

With a final class reference, we always know what function to call at compile time (since it can't be inherited). Therefore we don't need a vtable.

>
>> The problem isn't generating the vtable's. But the information required for casting.
>
> This applies to normal D classes, but D doesn't support (dynamic) casts for extern(C++) classes, anyway, so this shouldn't be an issue for them.
>
> [1] https://github.com/somzzz/druntime/blob/74882c8a48dd8a827181e3b89c4f0f205c881ac5/src/object.d#L50


September 10, 2017
On Sunday, 10 September 2017 at 15:12:12 UTC, Yuxuan Shui wrote:
> On Sunday, 10 September 2017 at 14:42:42 UTC, Moritz Maxeiner wrote:
>> On Sunday, 10 September 2017 at 14:04:20 UTC, rikki cattermole wrote:
>>> On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
>>>> If TypeInfo for extern(C++) classes is removed, couldn't final extern(C++) classes without base class and which don't implement any interfaces omit the vtable so that the following assert holds:
>>>> 
>>>> ---
>>>> final extern(C++) class Foo {}
>>>> static assert (__traits(classInstanceSize, Foo) == 0LU);
>>>> ---
>>>> 
>>>> The reason I ask is that fairly often I have an abstraction that's better suited as a reference type than a value type, but doesn't need any runtime polymorphy (or the monitor standard classes have). Structs + pointers are the only way I know of to avoid the (in this special case) unneeded vtable overhead, but it always ends up looking worse to read.
>>>
>>> We can do it for any class if its final.
>>
>> Even final classes can always inherit (potentially already overridden) virtual methods from their parent classes and since all normal D classes inherit from core.object : Object [1], which defines virtual methods (`toString`, `toHash`, `opCmp, and `opEquals`), I don't see how this can be true.
>
> With a final class reference, we always know what function to call at compile time (since it can't be inherited). Therefore we don't need a vtable.

---
class Base
{
    string name()
    {
        return "Base";
    }
}

class ChildA : Base
{
    override string name()
    {
        return "ChildA";
    }
}

final class ChildB : Base
{
    override string name()
    {
        return "ChildB";
    }
}

void foo(Base b)
{
    import std.stdio;
    b.name.writeln;
}

void main(string[] args)
{
    Base b;
    if (args.length > 1) b = new ChildA;
    else b = new ChildB;
    b.foo();
}
---

It is not known at compile time which class `foo`'s parameter `b` will actually be an instance of (Base, ChildA, or ChildB), so static dispatch is not possible; it requires dynamic dispatch. Since dynamic dispatch for classes is done in D via vtables, ChildB needs a vtable.
September 10, 2017
On Sunday, 10 September 2017 at 15:08:50 UTC, Yuxuan Shui wrote:
> By the way, can we dynamic_cast extern(C++) classes in C++?

It doesn't work for me OOTB with dmd 2.075, at least (though I may be missing something):

--- classes.d ---
import core.memory;

extern(C++) class Parent
{
    char id()
    {
        return 'P';
    }
}

extern(C++) class Child : Parent
{
    override char id()
    {
        return 'C';
    }
}

extern(C++) Parent makeParent()
{
  auto p = new Parent;
  GC.addRoot(cast(void*) p);
  return p;
}

extern(C++) Child makeChild()
{
  auto c = new Child;
  GC.addRoot(cast(void*) c);
  return c;
}

extern(C++) void releaseParent(Parent p)
{
  GC.removeRoot(cast(void*) p);
}

extern(C++) void releaseChild(Child c)
{
  GC.removeRoot(cast(void*) c);
}
-----------------

--- main.cc ---
#include <iostream>

class Parent
{
  public:
    virtual char id();
};

class Child : public Parent
{
};

extern Parent* makeParent();
extern Child* makeChild();

extern void releaseParent(Parent* p);
extern void releaseChild(Child* c);


extern "C" void rt_init();
extern "C" void rt_term();

bool isChild(Parent* p)
{
  return nullptr != dynamic_cast<Child*>(p);
}

int main(int argc, char** argv)
{
  rt_init();

  Parent* p = makeParent();
  Child* c = makeChild();

  std::cout << p->id() << "\n";
  std::cout << c->id() << "\n";

  std::cout << "identifier\tChild\n";
  std::cout << "p\t" << isChild(p) << "\t";
  std::cout << "c\t" << isChild(c) << "\t";

  releaseChild(c);
  releaseParent(p);

  rt_term();
  return 0;
}
---------------

--- Compile&Link ---
$ dmd -c classes.d
$ g++ -std=c++11 -o main main.cc classes.o -L/path/to/dmd-2.075/lib64/ -lphobos2
/tmp/ccwjJ9Xe.o: In function `isChild(Parent*)':
main.cc:(.text+0x20): undefined reference to `typeinfo for Parent'
/tmp/ccwjJ9Xe.o:(.rodata._ZTI5Child[_ZTI5Child]+0x10): undefined reference to `typeinfo for Parent'
collect2: error: ld returned 1 exit status
--------------------
September 10, 2017
On 9/10/2017 7:01 AM, Yuxuan Shui wrote:
> Is there a plan? Are there any simple tasks I can take/help?

I filed an enhancement request:

  https://issues.dlang.org/show_bug.cgi?id=17822

The rest is kinda up to me.
September 10, 2017
On 9/10/2017 8:08 AM, Yuxuan Shui wrote:
> By the way, can we dynamic_cast extern(C++) classes in C++?

No. Generally, one would need C++ RTTI for that to work, and that:

1. is specific to the particular C++ compiler
2. is undocumented, half-documented, or wrongly documented
3. requires the C++ runtime library to work

It's certainly possible to do this, but requires time, effort, and a certain willingness to deal with the dirty underbelly of undocumented binary formats.

> If not, what are we generating these TypeInfo_Class for?

It has other uses, such as providing info for associative arrays and the garbage collector.

1 2
Next ›   Last »