Re: Why does the importC example not compile?

2023-01-14 Thread Gavin Ray via Digitalmars-d-learn

On Friday, 13 January 2023 at 12:46:33 UTC, Dennis wrote:

On Friday, 13 January 2023 at 12:33:28 UTC, kdevel wrote:
What must be added or changed in order to test every example 
which is intended to produce an executable?


Support for separate compilation / ImportC would need to be 
added to dspec_tester:

https://github.com/dlang/dlang.org/blob/master/tools/dspec_tester.d


I ran into this issue too, what I discovered is that when you 
import `square`, it is importing the file `square.c` (if one 
exists).


Because you have a function called `square` in a file called 
`square`, confusingly, you want `square.square`. Hence the error 
message about trying to invoke parens `()` on a module.


If you rename the file to `my_c_funcs.c` and then you do:

```d
import std.stdio;
import my_c_funcs;

void main()
{
int i = 7;
writefln("The square of %s is %s", i, my_c_funcs.square(i));
}
```

```sh
(dmd-nightly)[user@MSI source]$ dmd app.d my_c_funcs.c
(dmd-nightly)[user@MSI source]$ ./app
The square of 7 is 49
```


Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)

2023-01-13 Thread Gavin Ray via Digitalmars-d-learn

On Friday, 13 January 2023 at 19:16:17 UTC, H. S. Teoh wrote:
On Fri, Jan 13, 2023 at 08:31:17AM -0800, Ali Çehreli via 
Digitalmars-d-learn wrote:

On 1/13/23 07:07, Gavin Ray wrote:

> This is "valid" D I hope?

Yes because static arrays are just elements side-by-side in 
memory. You can cast any piece of memory to a static array 
provided the length and alignment are correct.

[...]

Or to be more precise, cast the memory to a *pointer* to a 
static array of the right size.  Static arrays are by-value 
types; passing around the raw array will cause the array to be 
copied every time, which is probably not what is intended.



T


Thanks Teoh and Ali, I wound up passing a pointer to a static 
array.


If anyone is curious, here's the full WIP implementation -- it's 
for a toy database (Postgres-like) I'm writing for a hobby and 
learning project:


https://ldc.godbolt.org/z/Kvh7dv96c


Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)

2023-01-13 Thread Gavin Ray via Digitalmars-d-learn
Maybe it would be better to wrap the slice in a new class with an 
invariant?


Because what I want to do is:

1. Ensure that the length of the underlying referenced/pointed-to 
data is `PAGE_SIZE`

2. Benefit from the features of D that I can

The bounds-checking of slices saves a lot of headaches during 
development.


So maybe doing something like this might be better?

```d
struct Frame
{
ubyte[] data;

invariant
{
assert(data.length == PAGE_SIZE);
}
}

class BufferPool
{
align(PAGE_SIZE) ubyte[PAGE_SIZE * BUF_POOL_NUM_PAGES] data;
Frame[BUF_POOL_NUM_PAGES] frames;

this()
{
// mmap
foreach (i; 0 .. BUF_POOL_NUM_PAGES)
{
frame_idx_t frame_idx = cast(frame_idx_t) i;
			frames[frame_idx].data = data[frame_idx * PAGE_SIZE .. 
(frame_idx + 1) * PAGE_SIZE];

}
}
}
```







Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)

2023-01-13 Thread Gavin Ray via Digitalmars-d-learn

On Friday, 13 January 2023 at 14:57:40 UTC, Ali Çehreli wrote:

On 1/13/23 06:49, Gavin Ray wrote:

> I am curious if you can return something like
`ubyte[PAGE_SIZE]*` or
> `ref ubyte[PAGE_SIZE]`?

A simple cast seems to work:

enum PAGE_SIZE = 4096;
enum BUF_POOL_NUM_PAGES = 1024;
alias frame_idx_t = size_t;

ubyte[10_000] data;

ubyte[PAGE_SIZE]* get_page(frame_idx_t frame_idx)
{
auto ptr = data.ptr + frame_idx * PAGE_SIZE;
return cast(ubyte[PAGE_SIZE]*)ptr;
}

void main() {
}

Ali


Ah, much thanks Ali!

This is "valid" D I hope?

I searched Github for `"ubyte[4096]*"` and I found two uses of 
it, in the `xtrix` repo which seems to be an Operating System 
written in D:


![screenshot-of-ubyte-sized-ptr-on-github](https://i.imgur.com/WaAklbq.png)



Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)

2023-01-13 Thread Gavin Ray via Digitalmars-d-learn
I probably should have mentioned, the equivalent in C++ is the 
below:


```cpp
#include 
#include 
#include 

static constexpr size_t PAGE_SIZE  = 4096;
static constexpr size_t BUF_POOL_NUM_PAGES = 1024;

class BufferPool
{
  private:
alignas(PAGE_SIZE) std::byte data[BUF_POOL_NUM_PAGES * 
PAGE_SIZE];


  public:
BufferPool()
{
mmap(data, BUF_POOL_NUM_PAGES * PAGE_SIZE,
 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 
-1, 0);

}

// Return a fat-pointer of PAGE_SIZE bytes over the page, 
containing { T* ptr, len }

std::span get_page(size_t page_num)
{
return std::span(data + page_num * 
PAGE_SIZE, PAGE_SIZE);

}
};
```



Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)

2023-01-13 Thread Gavin Ray via Digitalmars-d-learn
Suppose that you have a memory manager, or arena-like class, 
which contains a buffer used to store memory.


And you want to hand out chunks of this memory to other parts of 
your program. These chunks should all be `PAGE_SIZE`.



You might have something like:

```d
enum PAGE_SIZE = 4096;
enum BUF_POOL_NUM_PAGES = 1024;

class BufferPool
{
align(PAGE_SIZE) ubyte[PAGE_SIZE * BUF_POOL_NUM_PAGES] data;

this()
{
mmap(, data.sizeof,
 PROT_READ | PROT_WRITE, MAP_ANONYMOUS | 
MAP_PRIVATE, -1, 0);

}
}
```

Now there should be a function, like `get_page()`, that returns a 
`PAGE_SIZE` pointer of `ubyte`. But I can only figure out how to 
return a `ubyte[]`:


```d
ubyte[] get_page(frame_idx_t frame_idx)
{
	return data[frame_idx * PAGE_SIZE .. (frame_idx + 1) * 
PAGE_SIZE];

}
```

I am curious if you can return something like `ubyte[PAGE_SIZE]*` 
or `ref ubyte[PAGE_SIZE]`?


Thank you =)





Re: Is defining get/set methods for every field overkill?

2022-11-18 Thread Gavin Ray via Digitalmars-d-learn

On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:

D has far less need for getters/setters than Java or C++. The 
reason is [Uniform Function Call 
Syntax](https://ddili.org/ders/d.en/ufcs.html). This means that 
a member of a `struct` or `class` can start out as a normal 
field and be later converted to getter/setter if needed, 
without breaking calling code.


This is a great point that I actually had never considered. If 
you need to swap out the implementation details later, you 
haven't actually locked yourself in to exposing the raw member 
because you swap it with a getter function/property of the same 
name. Huh. I love D.




Re: dmd 2.099 regression: unittest -checkaction=context and import std.regex cause lots of undefined references

2022-11-17 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 14 November 2022 at 20:37:12 UTC, kdevel wrote:

On Monday, 14 November 2022 at 17:08:38 UTC, Gavin Ray wrote:
Just came here to say I hit the same bug, here's my import 
list:


* https://issues.dlang.org/show_bug.cgi?id=19937
  object._d_assert_fail linker error if compiling with 
-checkaction=context


* https://issues.dlang.org/show_bug.cgi?id=22374
  [REG 2.093] 'import std;' with -checkaction=context causes 
link error


* https://issues.dlang.org/show_bug.cgi?id=22902
  dmd 2.099 regression: unittest -checkaction=context and 
import std.regex causes link error


Does `dmd -allinst ...` help in your case?


Hey, it does actually, thanks a bunch!


Re: dmd 2.099 regression: unittest -checkaction=context and import std.regex cause lots of undefined references

2022-11-14 Thread Gavin Ray via Digitalmars-d-learn

On Saturday, 28 May 2022 at 23:02:45 UTC, kdevel wrote:

On Friday, 18 March 2022 at 19:42:02 UTC, Anonymouse wrote:

On Thursday, 17 March 2022 at 14:00:45 UTC, kdevel wrote:
If ```import std.regex;``` is commented out or if 
```-checkaction=context``` is removed from the cmd line the 
unittest passes. Can anybody reproduce this?


https://run.dlang.io/is/GYDUBz

File an issue, I'd say. The worst thing that can happen is 
that someone flags it as a duplicate.


Issue 22902 - dmd 2.099 regression: unittest 
-checkaction=context and import std.regex causes link error 
(edit)

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


Just came here to say I hit the same bug, here's my import list:

```d
import std.typecons : Tuple;
import std.container : Array;
import std.format : format;
import std.stdio;
import std.file;
import std.conv;
import std.outbuffer;
import core.stdc.stdio;
import core.stdc.stdint;
import core.sys.posix.fcntl;
import core.sys.posix.unistd;
```


Re: Disk write in a "for" loop with RwMutex never happens

2022-08-29 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 29 August 2022 at 15:52:31 UTC, rikki cattermole wrote:
After a bunch of playing around I managed to determine that it 
is as simple as the mode.


exists(dbFileName) ? "r+" : "w+"



Will fix it.

Of course you shouldn't delete the file like that method is 
doing. It should probably reinitialize the FILE* descriptor.


D'oh!

I didn't even think about the mode:

  > `a+ or ab+ or a+b`
  > "Append; open or create file for update, writing at 
end-of-file."


It must have been the "writing at end of file" bit?

Thanks Rikki. /embarrassed


Re: Disk write in a "for" loop with RwMutex never happens

2022-08-29 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 29 August 2022 at 07:04:49 UTC, bauss wrote:

Does anyone know what is happening here? It's really puzzling.


You probably need to flush the output.


That's a good idea. I gave it a shot, and the following doesn't 
seem to change anything unfortunately:


```d
void writePage(PageId pageId, ubyte[PAGE_SIZE] pageData)
{
synchronized (dbIOMutex.writer)
{
dbFile.seek(pageId * PAGE_SIZE);
dbFile.rawWrite(pageData);
dbFile.flush();
dbFile.sync();
}
}
```


Disk write in a "for" loop with RwMutex never happens

2022-08-28 Thread Gavin Ray via Digitalmars-d-learn

I've put the code, stripped to a minimal example here:
- https://ldc.godbolt.org/z/fzsx3Tnnn

You can see that the single write + read version of the code 
works just fine:

```
pageData[0..4] = [1, 2, 3, 4]
readData[0..4] = [1, 2, 3, 4]
```

Where here, `pageData` is the data to be written to a file, and 
`readData` is the result of trying to read the freshly written 
file data.


But if the same code is placed inside of a `for` loop, suddenly 
no writes occur:

```d
pageData[0..4] = [0, 0, 0, 0]
readData[0..4] = [0, 0, 0, 0]

pageData[0..4] = [0, 0, 0, 1]
readData[0..4] = [0, 0, 0, 0]

pageData[0..4] = [0, 0, 0, 2]
readData[0..4] = [0, 0, 0, 0]

pageData[0..4] = [0, 0, 0, 3]
readData[0..4] = [0, 0, 0, 0]

pageData[0..4] = [0, 0, 0, 4]
readData[0..4] = [0, 0, 0, 0]

// ...
```

Does anyone know what is happening here? It's really puzzling.


Re: Fixed-size OutBuffer that doesn't call .resize() automatically? (for database page buffers)

2022-08-22 Thread Gavin Ray via Digitalmars-d-learn

Ahh, thanks a ton for these pointers, much appreciated!




Re: Fixed-size OutBuffer that doesn't call .resize() automatically? (for database page buffers)

2022-08-19 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 15 August 2022 at 22:47:21 UTC, frame wrote:

On Monday, 15 August 2022 at 20:51:07 UTC, Gavin Ray wrote:

Is there an alternative to `OutBuffer` or a method you can 
call to set a byte limit on the resizing?


Are you looking for a circular buffer?

https://code.dlang.org/packages/ringbuffer


Thanks for this suggestion, I hadn't considered it

I discovered 3 ways of doing it:

1. Calling `.toBytes()` on an `OutBuffer` will discard the extra 
bytes allocated past what was reserved and used. But this will 
still allocate the memory in the first place I guess (will the 
compiler optimize this away?)


2. Copy the `OutBuffer` class into a new `FixedSizeOutBuffer(T)` 
and alter its behavior


3. Use `ubyte[PAGE_SIZE]` and manually write like below:

```d
ubyte[] toBytes(uint value)
{
static ubyte[4] bytes = new ubyte[4];
bytes[0] = cast(ubyte)(value >> 24);
bytes[1] = cast(ubyte)(value >> 16);
bytes[2] = cast(ubyte)(value >> 8);
bytes[3] = cast(ubyte)(value);
return bytes;
}

void serialize(out ubyte[PAGE_SIZE] outbuf)
{
ubyte[] buf;
reserve(buf, PAGE_SIZE);

buf ~= toBytes(header.pageId);
buf ~= toBytes(header.logStorageNumber);
buf ~= toBytes(header.prevPageId);
buf ~= toBytes(header.nextPageId);
buf ~= toBytes(header.freeSpacePointer);
buf ~= toBytes(header.tupleCount);

foreach (idx, ref slot; header.slots)
{
buf ~= toBytes(slot.offset);
buf ~= toBytes(slot.size);
}

// Skip over free space
ubyte[] padding = new ubyte[header.freeSpacePointer];
padding[] = 0;
buf ~= padding;

foreach (idx, ref tuple; tuples)
{
buf ~= toBytes(tuple.size);
buf ~= tuple.data;
}

move(buf.ptr, outbuf.ptr);
}
```


Fixed-size OutBuffer that doesn't call .resize() automatically? (for database page buffers)

2022-08-15 Thread Gavin Ray via Digitalmars-d-learn
I'm learning about databases by implementing one from scratch, 
and decided I'd do it in D since it has the highest-level syntax 
for low-level code & seemed a natural fit.


Currently I am trying to implement the "slotted page" structure 
and storage (serialization/de-serialization from binary data 
on-disk)


"Slotted pages" are a data structure that store:

![](https://www.cs.swarthmore.edu/~soni/cs44/f18/Labs/images/2/heappage_array.jpg)

I tried to implement this using `OutBuffer`, but found that the 
buffer resized itself to greater than `PAGE_SIZE` bytes 
automatically =(


Is there an alternative to `OutBuffer` or a method you can call 
to set a byte limit on the resizing?


RUNNABLE DEMO: https://ldc.godbolt.org/z/ev78xos5b

```d
enum PAGE_SIZE = 4096;
enum HEADER_SIZE = (uint.sizeof) * 6;
enum TUPLE_SLOT_SIZE = (uint.sizeof) * 2;

struct TupleSlot
{
uint offset;
uint size;
}

struct Tuple
{
uint size;
ubyte[] data;
}

struct PageHeader
{
uint logStorageNumber = 0;
uint pageId = 0;
uint prevPageId = 0;
uint nextPageId = 0;
uint freeSpacePointer = PAGE_SIZE;
uint tupleCount = 0;
TupleSlot[] slots;
}

struct SlottedPage
{
PageHeader header;
Tuple[] tuples;
ubyte[PAGE_SIZE] buffer;

void insertTuple(Tuple tuple)
{
tuples ~= tuple;
header.slots ~= TupleSlot(header.freeSpacePointer, 
cast(uint) tuple.sizeof);

header.tupleCount++;
header.freeSpacePointer -= tuple.sizeof;
}

void serialize(OutBuffer buf)
{
with (header)
{
buf.write(pageId);
buf.write(logStorageNumber);
buf.write(prevPageId);
buf.write(nextPageId);
buf.write(freeSpacePointer);
buf.write(tupleCount);
}

foreach (TupleSlot slot; header.slots)
{
buf.write(slot.offset);
buf.write(slot.size);
}

buf.fill0(header.freeSpacePointer);

foreach (Tuple tuple; tuples)
{
buf.write(tuple.size);
buf.write(tuple.data);
}
}
}

void main()
{
OutBuffer buffer = new OutBuffer();
buffer.reserve(4096);

auto page = new SlottedPage(PageHeader());
foreach (i; 0 .. 10)
{
OutBuffer buf = new OutBuffer();
buf.write(i);
page.insertTuple(Tuple(cast(uint) buf.data.length, buf.data));
}

page.serialize(buffer);
// Writes 8206
writeln("Buffer size is: ", buffer.data.length);
}
```


Re: cloning array

2021-06-02 Thread Gavin Ray via Digitalmars-d-learn

On Wednesday, 2 June 2021 at 16:07:35 UTC, Basile.B wrote:
works a expected. The reason why is that your array elements 
are fat pointers, so when you dup a, you dup some fats pointer, 
so you got the same elements as "a" but accessible from another 
chunck of memory.


Would it be worth modifying the docs for `.dup()` so that this 
behavior is clear?


I would have been confused by this as well. It's probably a 
no-brainer if you understand general memory principles but not 
everyone does.


Re: Compiler Explorer Assembly Output for C, C++ and D (dlang)

2021-05-27 Thread Gavin Ray via Digitalmars-d-learn

On Thursday, 27 May 2021 at 10:48:43 UTC, Basile B. wrote:

https://forum.dlang.org/post/myrjutqyzpzlyltrd...@forum.dlang.org


Thank you for sharing this!

The difference between setting `pragma(LDC_no_moduleinfo);` at 
the top, and `-Os -gline-tables-only` in compiler flags is 
drastic.


- Standard
  - https://d.godbolt.org/z/env355M71
- No module info + flags
  - https://d.godbolt.org/z/4KxxvonY5


You wind up with
```c
int example.square(int):
mov eax, edi
imuleax, edi
ret
```

```
define i32 @_D7example6squareFiZi(i32 %num_arg) 
local_unnamed_addr #0 !dbg !5 {

  %1 = mul i32 %num_arg, %num_arg, !dbg !7
  ret i32 %1, !dbg !7
}

attributes #0 = { norecurse nounwind readnone uwtable 
"frame-pointer"="none" "target-cpu"="x86-64" 
"target-features"="+cx16" }

```


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Gavin Ray via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 18:03:00 UTC, evilrat wrote:
That last one with someInt is what I warned about. D ctor 
messed up class layout, in this simple case where class data 
isn't used it almost works, but will be practically unusable in 
real scenarios.


Ah =/
You have this in your code example:
```d
static assert(Derived.someInt.offsetof == 16); // that's 
important otherwise D ctor will mess up everything

```

Would this fix it, or is it just not super viable to hack around 
C++ multiple inheritance in D?


Maybe generating some wrapper C++ code to be linked could help 
too?

I'm not sure though/don't really know enough to say



Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Gavin Ray via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 11:38:03 UTC, evilrat wrote:
I did some basic testing with code above, it seems class layout 
is recursively linear at least on Windows, and D follows C++ 
rules close enough, at least it works if one comments out all 
but the first base, and the rest can be hand crafted using 
structs and templates.



With this code it is possible to pass back C++ class received 
from C++ code and call it.
So it seems support for multiple inheritance shouldn't be that 
hard to implement (for Windows), no idea how it works on Linux 
though.


Maybe I'll be able to create templated base class that does all 
this stuff with mixins and templates.


like this
```d
extern(C++)
abstract class MultipleInheritance(T...)
{
  // implementation //
}

class Derived : MultipleInheritance!(Base1, Base2)
{ ... }
```


Oh this is brilliant! Absolutely incredible work + findings!

Is this conceptually similar at all to this bit of code that adr 
had given to me?

```d
// Same thing repeated for Abstract2
interface Abstract1 {
/* virtual */ void overrideMe1();
void sayHello();
mixin template Abstract1Impl() {
void sayHello() { import std.stdio; writeln("Hello"); }
}
}

class MyClass : Abstract1, Abstract2 {
  mixin Abstract1Impl; mixin Abstract2Impl;
  override void overrideMe1() { writeln("overrode 1"); }
  override void overrideMe2() { writeln("overrode 2"); }
}

void main() {
auto it = new MyClass();
it.sayHello(); it.sayGoodbye();
it.overrideMe1(); it.overrideMe2();
}
```

---

Also, I wonder if there's a good way to build a quick CLI 
visualization + debugging tool for this using D's `.vtble[]` 
method. I would find it really useful for learning =D


There are also some automatic ABI compliance checker 
tools/libraries, which could be good for programmatically 
verifying that the class produced by D is valid with the ABI of a 
method/class from a C++ library file.


(I know for example, that Qt does this with their Python codegen 
tool, `Shiboken`, for auto-testing the generated code)


- 
https://sourceware.org/libabigail/manual/libabigail-overview.html
- https://github.com/lvc/abi-compliance-checker (this is what 
Shiboken is/was using)


... libabigail provides facilities to perform deep comparisons 
of two ABIs. That is, it can compare the types of two sets of 
functions or variables and represents the result in a way that 
allows it to emit textual reports about the differences.


This allows us to write tools like `abidiff` that can compare 
the ABI of two shared libraries and represent the result in a 
meaningful enough way to help us spot ABI incompatibilities. 
There are several other tools that are built using the Abigail 
framwork.


```sh
$ g++ -g -Wall -shared -o libtest-v0.so test-v0.cc
$ g++ -g -Wall -shared -o libtest-v1.so test-v1.cc
$
$ ../build/tools/abidiff libtest-v0.so libtest-v1.so
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

1 function with some indirect sub-type change:

  [C]'function void foo(S0&)' has some indirect sub-type changes:
parameter 0 of type 'S0&' has sub-type changes:
  in referenced type 'struct S0':
size changed from 32 to 64 bits
1 data member insertion:
  'char S0::inserted_member', at offset 0 (in bits)
1 data member change:
 'int S0::m0' offset changed from 0 to 32
```




Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Gavin Ray via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 06:02:55 UTC, evilrat wrote:
Anyway all this stuff requires thorough research & testing as 
such ABI tinkering is very easy to mess up and very hard to 
debug, for example if you mess up the order(functions layout) 
it can land on another final method call that seemingly work 
but in debugger you'll see that you can't hit breakpoint in 
that method.

Happy debugging time!


Ahh, that works!

It also works without the `cast(BaseType)` if you use `alias` in 
the class:

```d
import core.stdc.stdio : printf;
extern (C++)
{
  void takesADerived(Derived derived);
  Derived createTestDerivedCPP();

  extern interface Base1
  {
void overrideMe1();

pragma(mangle, "?getSomething@Base1@@QEAA?BHXZ")
final int getSomething();

pragma(mangle, "?inheritedFunctionWithArgs@Base1@@QEAAHHH@Z")
final int inheritedFunctionWithArgs(int x, int y);
  }

  extern interface Base2
  {
void overrideMe2();

pragma(mangle "?getOtherThing@Base2@@QEAA?BHXZ")
final int getOtherThing();
  }

  extern class Derived : Base1, Base2
  {
int someInt;

alias getSomething = Base1.getSomething;
alias inheritedFunctionWithArgs = 
Base1.inheritedFunctionWithArgs;


this(int someIntVal) { this.someInt = someIntVal; }

void overrideMe1() { printf("[D] Dlang Derived overrideMe1 
called \n"); }
void overrideMe2() { printf("[D] Dlang Derived overrideMe1 
called \n"); }

  }
}

void main()
{
  Derived dlangDerived = new Derived(123);
  printf("[D] Derived.Base1::getSomething() = %d \n", 
dlangDerived.getSomething());
  printf("[D] Derived.Base2::getOtherThing() = %d \n", 
dlangDerived.getOtherThing());
  printf("[D] Derived.Base1::inheritedFunctionWithArgs(5, 10) = 
%d \n",

  dlangDerived.inheritedFunctionWithArgs(5, 10));
  printf("[D] Calling C++ takesADerived() with D Derived* \n");
  takesADerived(dlangDerived);
}
```

![output](https://i.imgur.com/Plbtlow.png)

Just you wait, I'll learn enough to be of any use contributing to 
OMG yet! haha


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 24 May 2021 at 20:31:18 UTC, sighoya wrote:

On Monday, 24 May 2021 at 17:39:38 UTC, Gavin Ray wrote:
Hence why I was asking how to make D structs/classes that have 
compatible or identical vtables to multiply inherited objects 
to pass as arguments to `extern (C++)` functions.


I think classes annotated with extern is your only high level 
guaranteed == type safe option to be compatible to other c++ 
classes.


But you seek for the general multiple inheritance case which 
seems not to be supported with `extern`, sadly.
So you stick with manual solutions like template 
metaprogramming or/and raw pointer fiddling.
Anyway, both solutions would require an unsafe cast in the end, 
so you are on your own.


The below seems to work at least, which is encouraging:

```cpp
#include 
#define DLL_EXPORT __declspec(dllexport)

class Base1 {
public:
virtual void overrideMe1() = 0;
const int getSomething() { return 42; }
};

class Base2 {
public:
virtual void overrideMe2() = 0;
const int getOtherThing() { return 99; }
};

class Derived : public Base1, public Base2 {
public:
int someInt;
Derived(int someIntVal) { this->someInt = someIntVal; }
virtual void overrideMe1() override;
virtual void overrideMe2() override;
};

DLL_EXPORT void takesADerived(Derived* derived)
{
printf("[C++] Calling Derived::overrideMe1() \n");
derived->overrideMe1();
printf("[C++] Calling Derived::overrideMe2() \n");
derived->overrideMe2();
printf("[C++] Calling Derived::getSomething() = %d \n",
derived->getSomething());
printf("[C++] Calling Derived::getOtherThing() = %d \n",
derived->getOtherThing());
printf("[C++] Derived::someInt = %d \n", derived->someInt);
}
```

```d
import core.stdc.stdio : printf;

extern (C++)
{
  void takesADerived(Derived derived);

  interface Base1 { void overrideMe1(); }
  interface Base2 { void overrideMe2(); }
  class Derived : Base1, Base2
  {
int someInt;
this(int someIntVal) { this.someInt = someIntVal; }
void overrideMe1() { printf("[D] Dlang Derived overrideMe1 
called \n"); }
void overrideMe2() { printf("[D] Dlang Derived overrideMe1 
called \n"); }

  }
}

void main()
{
  auto dlangDerived = new Derived(123);
  printf("[D] Calling C++ takesADerived() with D Derived* \n");
  takesADerived(dlangDerived);
}
```

![example](https://media.discordapp.net/attachments/242122752436338688/846565538163195974/unknown.png)

Unfortunately, it does not work if I try to add `final int 
getSomething()` or the other one to the D interfaces, it throws a 
symbol error because the mangled names are slightly different:


```sh

unresolved external symbol "public: int __cdecl 
Base1::getSomething(void)"

  (?getSomething@Base1@@QEAAHXZ)
 T ?getSomething@Base1@@QEAA?BHXZ # < "nm" output
```

If I use `nm` and list the symbols, and then try to manually use 
the mangling scheme, it almost works but because the return types 
differ it won't compile =/

```d
extern class Derived : Base1, Base2
{
  int someInt;

  pragma(mangle, "?getOtherThing@Base2@@QEAA?BHXZ")
  int getOtherThing();
}
```

```sh
main.d(29): Error: Function type does not match previously 
declared function with the same mangled name: 
`?getOtherThing@Base2@@QEAA?BHXZ`

main.d(29):Previous IR type: i32 (%main.Base2*)
main.d(29):New IR type:  i32 (%main.Derived*)
```




Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Gavin Ray via Digitalmars-d-learn

On Sunday, 23 May 2021 at 21:08:06 UTC, Ola Fosheim Grostad wrote:

On Sunday, 23 May 2021 at 21:02:31 UTC, Gavin Ray wrote:
I don't really know anything at all about compilers or 
low-level code -- but is there any high-level notion of 
"inheritance" after it's been compiled?


Yes, in the structure of the vtable, which is why the spec is 
so hard to read.


If possible stick to single inheritance in C++...


Yeah agreed, multiple inheritance is asking for trouble.

But unfortunately when you're binding to existing libraries you 
don't have control over the API


Hence why I was asking how to make D structs/classes that have 
compatible or identical vtables to multiply inherited objects to 
pass as arguments to `extern (C++)` functions.


Also general explanation of what makes a compiled variable 
compatible in terms of vtable with what's expected as an argument


I'd be grateful for solid information on this


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-23 Thread Gavin Ray via Digitalmars-d-learn

On Sunday, 23 May 2021 at 20:16:17 UTC, Ola Fosheim Grostad wrote:

On Sunday, 23 May 2021 at 19:44:01 UTC, Gavin Ray wrote:
So one of the problems with generating D code for bindings to 
C++ is that there's no true/direct multiple inheritance.


If anyone happens to understand well how vtables work and the 
way the compiler treats these things, is there a way to 
hackily make semantically-equivalent objects?


I believe Clang and MSVC are using different layouts.
If I am not wrong clang/gcc are using the Itanium ABI, but I 
could be wrong.


https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable

Maybe ask in the LDC forum as they follow Clang? In my opinion 
MI ought to be supported for binding, but... not sure if anyone 
has considered it.


I guess that's maybe a better way of what I'm asking -- whether 
the vtable is all that matters.


Because I've seen C ABI's for C++ API's that have multiple 
inheritance, and the code was like this (I'll just post a single 
inheritance example but you get the point):


```cpp
class FUnknown {
tresult queryInterface(void*, const TUID, void**);
uint32* addRef(void *);
uint32* release(void *);
};

class IComponentHandler : FUnknown {
tresult beginEdit(void *, ParamID);
tresult performEdit(void *, ParamID, ParamValue);
tresult endEdit(void *, ParamID);
tresult restartComponent(void *, int32);
};

#ifdef __cplusplus
extern "C" {
#endif
typedef struct FUnknownVTable {
tresult (*queryInterface)(void *, const TUID, void **);
uint32 (*addRef)(void *);
uint32 (*release)(void *);
} FUnknownVTable;

typedef struct SFUnknown {
FUnknownVTable *vtable;
} SFUnknown;

typedef struct IComponentHandlerVTable {
FUnknownVTable FUnknown;
tresult (*beginEdit)(void *, ParamID);
tresult (*performEdit)(void *, ParamID, ParamValue);
tresult (*endEdit)(void *, ParamID);
tresult (*restartComponent)(void *, int32);
} IComponentHandlerVTable;

typedef struct SIComponentHandler {
IComponentHandlerVTable *vtable;
} SIComponentHandler;

#ifdef __cplusplus
}
#endif
```

I don't really know anything at all about compilers or low-level 
code -- but is there any high-level notion of "inheritance" after 
it's been compiled?


I felt like it had to turn into something like blocks of memory 
that have pointers to methods and/or to other blocks of memory 
with pointers to methods (vtables). But I also have no clue 樂





How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-23 Thread Gavin Ray via Digitalmars-d-learn
So one of the problems with generating D code for bindings to C++ 
is that there's no true/direct multiple inheritance.


If anyone happens to understand well how vtables work and the way 
the compiler treats these things, is there a way to hackily make 
semantically-equivalent objects?


An example:

```cpp
class Kickable {
  void nonVirtual() { /* impl */ }
  virtual void kick();
}

class Throwable {
  virtual void throw();
}

class KickableThrowable : Kickable, Throwable {}

// KickableThrowable or KickableThrowable*, not really sure which 
is more realistic

void takesKickableThrowable(KickableThrowable* thing) {}
```

Would making a class/struct that has the methods `nonVirtual()`, 
`kick()`, and `throw()` be usable as an argument to 
`takesKickableThrowable()`, since it would contain identical 
members/layout?


```d
extern (C++)
class KickableThrowable {
   void nonVirtual();
   /* override */ void kick() {}
   /* override */ void kick() {}
}

extern (C++)
void takesKickableThrowable(KickableThrowable thing);

takesKickableThrowable(new KickableThrowable());
```

adr had shown me a way to mimic multiple inheritance using 
interfaces and mixin templates, would this be a viable approach?


- See: https://run.dlang.io/is/3rJyMt

```d
interface Abstract1 {
/* virtual */ void overrideMe1();

void sayHello();
mixin template Abstract1Impl() {
void sayHello() { import std.stdio; writeln("Hello"); }
}
}

interface Abstract2 {
/* virtual */ void overrideMe2();

void sayGoodbye();
mixin template Abstract2Impl() {
void sayGoodbye() { import std.stdio; writeln("Goodbye"); 
}

}
}

class MyClass : Abstract1, Abstract2 {
  mixin Abstract1Impl;
  mixin Abstract2Impl;
  override void overrideMe1() { writeln("overrode 1"); }
  override void overrideMe2() { writeln("overrode 2"); }
}
```

---

Also, what is the best way to debug and learn about vtables and 
their impact on interopability in D?


Visual Studio has the "Struct Layout" extension (pictured below), 
and `clang` and `cl.exe` have options to dump vtable/record 
layouts:


```
$ cl.exe test.cpp /d1reportSingleClassLayoutMEOW

class BatMEOW   size(40):
+---
 0  | +--- (base class Mammal)
 0  | ::Breathe

BatMEOW::$vftable@WingedAnimal@:
| -16
 0  | ::Flap



BatMEOW::{dtor} this adjustor: 32
BatMEOW::__delDtor this adjustor: 32
BatMEOW::__vecDelDtor this adjustor: 32
vbi:   class  offset o.vbptr  o.vbte fVtorDisp
  Animal  32   8   4 0
```

```
$ clang -cc1 -fdump-vtable-layouts -emit-llvm  test.cpp

VFTable for 'Animal' (3 entries).
   0 | Animal RTTI
   1 | Animal::~Animal() [scalar deleting]
   2 | void Animal::Eat()


```

```
$ clang -cc1 -fdump-record-layouts -emit-llvm  test.cpp

*** Dumping AST Record Layout
 0 | struct Animal
 0 |   (Animal vftable pointer)
   | [sizeof=8, align=8,
   |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
 0 | struct Mammal
 0 |   (Mammal vftable pointer)
 8 |   (Mammal vbtable pointer)
16 |   struct Animal (virtual base)
16 | (Animal vftable pointer)
   | [sizeof=24, align=8,
   |  nvsize=16, nvalign=8]

```

![vtable inspector cpp](https://i.imgur.com/Xqw6jKG.gif)





Re: How to declare "type of function, passed as an argument, which should have it's type inferred"? (or if D had an "any" type)

2021-03-29 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 29 March 2021 at 17:02:40 UTC, evilrat wrote:


Also with delegates (lazy), you get the type checks however you 
must have to declare parameters on call site, which can be PITA 
in the future when doing refactoring will be necessary.


Better plan ahead as the number of changes will explode when 
you make quite a number of these and decide to change 
params/returns.


```
  import std.stdio;

  void my_func(T, XS)(string a, string b, string c, lazy T 
function(XS)[] t...)

  {
// call function, just the first one, can call all of them 
as well

t[0](a);

// can get the result too, mind the future refactoring 
needs tho

// T res = t[0]();
  }

  void main()
  {
my_func("name", "description", "otherthing", (string x) {
  writeln(x);
  return x;
});

// no function, compile error
// my_func("name", "description", "otherthing");
  }
```

---

Trying to read this function signature:

void my_func(T, XS)(string a, string b, string c, lazy T 
function(XS)[] t...)


Does this say "Generic void function 'my_func', which takes two 
generic/type params "T" and "XS", and is a function of type 
"string a, string b, string c", and..." (this is where it starts 
to get hazy for me):


How does one interpret/read this:

   lazy T function(XS)[] t...

Also I noticed that no explicit generic types were provided in 
your call. I assume this means that D's type system is similar to 
Typescript's then, where it's a logical constraints and will try 
to "fit the holes" so to speak.


In Typescript it works like this:

  function myFunc(arg: T) {}
  myFunc(1) // T is inferred to be type "number"
  myFunc("a") // T is inferred to be type "string"
  myFunc(1) // Same as above, but explicit, maybe useful 
if you want to verify arg, else pointless


It seems like potentially D is similar here?



Re: How to declare "type of function, passed as an argument, which should have it's type inferred"? (or if D had an "any" type)

2021-03-29 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 29 March 2021 at 16:31:49 UTC, Paul Backus wrote:

On Monday, 29 March 2021 at 16:20:59 UTC, Ali Çehreli wrote:

auto myFunc(F)(string name, F func)
{
  // This condition could be a template constraint but they 
don't

  // support error messages.
  static assert (is (Parameters!func == AliasSeq!(string)),
 "'func' must be a callable that takes 
'string'.");

  return func(name);
}

void main() {
  // One trouble with this "solution" is that for the compiler 
to

  // know the return type of the lambda, the parameter must be
  // declared as 'string' (in this case).
  writeln(myFunc("foo", (string a) => a ~ '.'));
}

Ali


Alternatively:

auto myFunc(F)(string name, F func)
{
  static assert (__traits(compiles, (string s) => func(s)),
 "'func' must be a callable that takes 
'string'.");

  return func(name);
}

void main() {
  // No need to write out the argument type
  writeln(myFunc("foo", a => a ~ '.'));
}

You can generalize this into a helper template:

enum bool isCallableWith(alias fun, ArgTypes...) =
  __traits(compiles, (ArgTypes args) => fun(args));

Usage:

static assert(isCallableWith!(func, string));




Ah that was even easier than I had made it out to be, thank you 
folks!


The part about needing to define the argument types to the lambda 
is no problem either (it was a silly transcription mistake on my 
end).


I actually need those argument types for later, to generate code 
based on them (translating D arg types -> a subset of C types, 
for building a translated function signature string to give to 
another app) so it works out =D


Much appreciated.


How to declare "type of function, passed as an argument, which should have it's type inferred"? (or if D had an "any" type)

2021-03-29 Thread Gavin Ray via Digitalmars-d-learn
Brief question, is it possible to write this so that the "alias 
fn" here appears as the final argument?


  auto my_func(alias fn)(string name, string description, auto 
otherthing)


The above seems to work, since the type of "fn" can vary and it 
gets called inside of "my_func", but from an ergonomics point I'd 
love to be able to put the function last and write it inline:


  my_func("name", "description", "otherthing", (x, y, z) {
auto foo = 1;
return foo + 2;
  })


Currently I am calling it like:

  auto some_func = (x, y, z) {
auto foo = 1;
return foo + 2;
  };

  my_func!some_func("name", "description", "otherthing");

Which is fine, it's just that from a readability perspective it 
doesn't really allow for writing the function inline and you need 
to declare it separately.


Not a huge deal, just learning and thought I would ask =)

Thank you!