Re: Remove elements without losing capacity
On Tuesday, 4 October 2022 at 18:18:41 UTC, Ali Çehreli wrote: On 10/4/22 10:59, Riccardo M wrote: > The inherent reason for `remove` to cancel previous capacity and > requiring new allocations is exactly to prevent overwriting data that > could be owned by something else? Yes. A related topic is how the "end slice" never loses that capacity: void main() { auto a = [ 1, 2 ]; auto b = a; assert(a.capacity != 0); assert(b.capacity != 0); b.length--; assert(b.capacity == 0); assert(a.capacity != 0);// <-- Preserved } Aside: .capacity is an expensive operation that requires some levels of table lookups in the druntime. A data structure would benefit a lot if it kept its own capacity as a member variable. Ali Wonderful. Thanks for the insight,
Re: Remove elements without losing capacity
On Tuesday, 4 October 2022 at 15:42:21 UTC, Steven Schveighoffer wrote: Yes, you use `assumeSafeAppend`: ```d arr.length--; arr.assumeSafeAppend; assert(arr.capacity != 0); ``` Now, I want to clarify that you should only use this if you are sure you are done with the data you removed at the end, as it will get overwritten upon more appends to the array. [...] Thanks! I can use the unstable `remove` and then restore the original capacity with `assumeSafeAppend` in case data can be safely overwritten. The inherent reason for `remove` to cancel previous capacity and requiring new allocations is exactly to prevent overwriting data that could be owned by something else?
Re: Interfacing with basic C++ class
On Friday, 30 September 2022 at 22:56:06 UTC, Ogi wrote: On Thursday, 29 September 2022 at 12:49:06 UTC, Riccardo M wrote: When interfacing to C++, disregard the keyword and look at the implementation instead. If all its member functions are non-virtual, map it to struct. Otherwise map it to class. If it defines at least one pure virtual member function, map it to abstract class. If all its member functions are either pure virtual or non-virtual and it contains no fields, map it to interface. Sounds complicated? Well, that’s because C++ is complicated. Ok, in layman terms, is it correct to say that I should match the underlining structure of the object (e.g in terms of vtbl) so that C++ side and D side can work with each other correctly? In C++, member functions defined inside its class are called *inline* member functions. In contrast to normal functions which must be defined once and only once in your program, inline functions must be defined in every translation unit that uses them. Let’s replicate your linking error in C++: Well, I didn't know the implications of inlining member functions: basically when a member function is inlined, it has no linkage so I am pretty much done with using D in such case. While in C++ you can import the header and call the member function anyway. The only solution would be reimplementing the offending function on D side.
Re: Interfacing with basic C++ class
On Thursday, 29 September 2022 at 11:13:15 UTC, Ogi wrote: Ali is correct. However, you don’t have to change anything on the C++ side, just map C++ class to D struct: [...] Thanks, this works perfectly. Now i see that I can even instantiate directly from D, calling the default ctor, calling the custom ctor or even overriding the custom ctor in D (the fact that ctors could be called, in contrast with docs, was in fact hinted at DConf 2022 as suggested by Ali). So it turns out that D's structs are a much better match for C++'s classes in this case. But why is this? Can you elaborate? It must have to do with the fact that D structs are passed by value? Now this D code runs as expected: ``` // D extern(C++, class) { struct MyClass { public: int field; this(int a); int add(int asd); } MyClass* instantiate(int asd); } void main() { import std : writeln; auto myclass = instantiate(100); //actually, instantiation through C++ is not required any longer assert(myclass.field == 100); auto myclass2 = new MyClass; assert(myclass2.field == 0); auto myclass3 = new MyClass(50); assert(myclass3.field == 50); assert(myclass3.add(40) == 90); } ``` However the 'add' function only links correctly if C++ has the function body defined outside of its class. ``` // C++ int MyClass::add(int asd) { return field + asd; } ``` If the function is defined inside its class, it is an undefined reference at link time. Once again I ask for clarifications and workarounds, if possible. Thanks
Re: Interfacing with basic C++ class
On Wednesday, 28 September 2022 at 20:41:13 UTC, Ali Çehreli wrote: [...] Ali Thank you, that is perfect! However that begs the following observation: it would be rather hard to link to a C++ library only by means of 'extern (C++)' if one should slightly rearrange C++ code as well. This sounds like it is rather obvious to the community, actually, but I am a recent addition to D language :) Do you know that this is documented somewhere? The examples in the official docs are rather limited, maybe studying a github with previous work might help. Cheers
Interfacing with basic C++ class
I think I am stuck in the easiest of the issues and yet it seems I cannot get around this. I have a C++ file: ``` class MyClass { public: int field; MyClass(int a) : field(a) {} int add(int asd) { return asd + 1; } }; MyClass* instantiate(int asd) { return new MyClass(asd); } ``` and a D file: ``` extern(C++) { class MyClass { public: int field; @disable this(); final int add(int asd); } MyClass instantiate(int asd); } void main() { import std : writeln; auto myclass = instantiate(100); writeln(myclass.field); } ``` This is a very simplified version of the dlang official example of interfacing with C++ classes. When I compile, I can't correctly read 'field'. What I do: ``` g++ -c cpp.cpp dmd app.d cpp.o -L-lstdc++ ./app ``` What I get: ``` 0 ``` Instead of the expected 100. Care to help me understand what am I doing wrong? Side question: it seems that I need to declare every class method as "final" otherwise I get undefined references during linking. Is this expected behaviour? Thanks