Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 14:33:56 UTC, Basile B. wrote: [...] Now there is still the question whether the `extern(C)` code will work as expected or not. So with few patches could we make it work? DMD can write the C++ function prototype (as it does it with `extern (C)`) and then mangle it as the template it uses in C?
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 14:21:49 UTC, Paul Backus wrote: On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote: [...] `extern(C++)` functions use C++ name mangling, which includes the types of the parameters in the mangled name. However, since C++ does not have a built-in slice type like D's `T[]`, there is no valid C++ mangling for a D slice. Because of this, it is impossible to compile an `extern(C++)` function that has a D slice as a parameter. [...] Simply add perfectly explained!
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 14:33:56 UTC, Basile B. wrote: On Saturday, 4 November 2023 at 13:51:20 UTC, Dadoum wrote: [...] The type simply cannot be mangled using the C++ mangler as it does not exist over there. You might have the impression that this should be allowed, e.g as an extension, but keep in mind that `extern(C++)` is firstly designed to link against object produced by a C++ compiler. Now why this works in `extern(C)` ? Because C does not mangle the parameters, a function linkage name is simply its unqualified name, so linking will work even if the parameter types are specific to D. Now there is still the question whether the `extern(C)` code will work as expected or not. Could the mangling be provided with pragma and made to work?
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 13:51:20 UTC, Dadoum wrote: On Saturday, 4 November 2023 at 13:45:56 UTC, Emmanuel Danso Nyarko wrote: [...] There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string' I don't think it's related to the existence of std::string at all since all dynamic array types are forbidden. ```d extern (C++) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` also fails to compile while this works: ```d extern (C) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` Here too you will get the same error, cannot be mapped to C++. C++ mangles dynamic arrays as pointer arrays(uses the 'P' symbol), which is supported by D for interfacing with C. Another disagreement here using it in c++ interop. Hence will not compile. Once again, I think the compiler team will be the best to give you what you're looking for.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 14:21:49 UTC, Paul Backus wrote: [...] `extern(C++)` functions use C++ name mangling, which includes the types of the parameters in the mangled name. However, since C++ does not have a built-in slice type like D's `T[]`, there is no valid C++ mangling for a D slice. Because of this, it is impossible to compile an `extern(C++)` function that has a D slice as a parameter. As a workaround, you can convert the slice to a `struct`: [...] I use another workaround myself: ```d extern (C++) struct List(T) { // or extern (C) T[] self; alias self this; } extern (C++) void hello(List!ubyte arg) { import std.stdio; writeln(arg); } ``` but it means adding a lot of edge cases to the mixins I use for bindings while showing that C++ can express D arrays. (translated to ```c++ template struct List final { _d_dynamicArray< T > self; List() { } }; extern void hello(List arg); ``` )
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 13:51:20 UTC, Dadoum wrote: On Saturday, 4 November 2023 at 13:45:56 UTC, Emmanuel Danso Nyarko wrote: [...] There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string' I don't think it's related to the existence of std::string at all since all dynamic array types are forbidden. ```d extern (C++) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` also fails to compile while this works: ```d extern (C) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` The type simply cannot be mangled using the C++ mangler as it does not exist over there. You might have the impression that this should be allowed, e.g as an extension, but keep in mind that `extern(C++)` is firstly designed to link against object produced by a C++ compiler. Now why this works in `extern(C)` ? Because C does not mangle the parameters, a function linkage name is simply its unqualified name, so linking will work even if the parameter types are specific to D. Now there is still the question whether the `extern(C)` code will work as expected or not.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote: I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++. `extern(C++)` functions use C++ name mangling, which includes the types of the parameters in the mangled name. However, since C++ does not have a built-in slice type like D's `T[]`, there is no valid C++ mangling for a D slice. Because of this, it is impossible to compile an `extern(C++)` function that has a D slice as a parameter. As a workaround, you can convert the slice to a `struct`: ```d struct DSlice(T) { T* ptr; size_t length; T[] opIndex() => ptr[0 .. length]; } DSlice!T toDslice(T)(T[] slice) { return DSlice!T(slice.ptr, slice.length); } extern(C++) void hello(DSlice!(const(char)) arg) { import std.stdio; writeln(arg[]); } void main() { const(char)[] greeting = "hello"; hello(greeting.toDslice); } ```
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 13:45:56 UTC, Emmanuel Danso Nyarko wrote: [...] There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string' I don't think it's related to the existence of std::string at all since all dynamic array types are forbidden. ```d extern (C++) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` also fails to compile while this works: ```d extern (C) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ```
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 12:34:28 UTC, Dadoum wrote: On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote: [...] So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. So you could see that D strings are possibly built on the architecture of C strings. In C++, string is a complex standard template library that generates complex symbols and cannot be mapped as it is based on a standard library implementation. I don't think the strings are being translated in any way when we change the linkage. Strings in D are dynamic arrays of chars, the C binding code is giving us a template representing D's dynamic arrays, and so I thought that we could also use it in C++ for interoperability with D dynamic arrays. There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string'
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 12:21:45 UTC, Johan wrote: On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote: On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote: ```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h` So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. This is not true. D string (=slice) variables store the length of the string in addition to the reference to the array of characters. The reason this "works" with `extern (C)` is because the C mangling of a function name does not include the type of the parameters. Note that C does not have a `string` type, so to call the function from C you will have to write a different function signature in C (you'll see that `char[]` will not work). It does not work with `extern(C++)` because the C++ mangling of a function _does_ include the type of the parameters, and there is no built-in C++ type that is equivalent to D's `string`. -Johan You're right but that's not what he's looking for I think. He wants to understand why it doesn't compile at all. One major cause of failed compilation is syntax disagreements And my main point is that because C++ doesn't know independent 'string' and that the string in C++ is a standard template library, the D compiler decides to stop any symbol generated interaction with string because C++ syntatically doesn't know 'string'. Maybe the compiler team could provide a better answer to him but that's what I think.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote: [...] So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. So you could see that D strings are possibly built on the architecture of C strings. In C++, string is a complex standard template library that generates complex symbols and cannot be mapped as it is based on a standard library implementation. I don't think the strings are being translated in any way when we change the linkage. Strings in D are dynamic arrays of chars, the C binding code is giving us a template representing D's dynamic arrays, and so I thought that we could also use it in C++ for interoperability with D dynamic arrays.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote: On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote: ```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h` So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. This is not true. D string (=slice) variables store the length of the string in addition to the reference to the array of characters. The reason this "works" with `extern (C)` is because the C mangling of a function name does not include the type of the parameters. Note that C does not have a `string` type, so to call the function from C you will have to write a different function signature in C (you'll see that `char[]` will not work). It does not work with `extern(C++)` because the C++ mangling of a function _does_ include the type of the parameters, and there is no built-in C++ type that is equivalent to D's `string`. -Johan
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 12:07:12 UTC, Imperatorn wrote: [...] We can just assume what you're doing on the C++-side. Are you using std::string? You could try as a pointer + length and it might work, but without seeing your complete code it's quite hard to know what you want to do. I will use whatever D gives me in the C++ header, because in fact I am using Swift on the other side, so using std::string isn't useful. I already made a conversion function from Swift strings to D strings when they are represented with C linkage.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 12:21:45 UTC, Johan wrote: On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote: On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote: ```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h` So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. This is not true. D string (=slice) variables store the length of the string in addition to the reference to the array of characters. The reason this "works" with `extern (C)` is because the C mangling of a function name does not include the type of the parameters. Note that C does not have a `string` type, so to call the function from C you will have to write a different function signature in C (you'll see that `char[]` will not work). It does not work with `extern(C++)` because the C++ mangling of a function _does_ include the type of the parameters, and there is no built-in C++ type that is equivalent to D's `string`. -Johan What I don't understand is why it cannot use the template it defines in the header. Here it is: ```c++ // Automatically generated by LDC Compiler #pragma once #include #include #include #include #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE #else /// Represents a D [] array template struct _d_dynamicArray final { size_t length; T *ptr; _d_dynamicArray() : length(0), ptr(NULL) { } _d_dynamicArray(size_t length_in, T *ptr_in) : length(length_in), ptr(ptr_in) { } T& operator[](const size_t idx) { assert(idx < length); return ptr[idx]; } const T& operator[](const size_t idx) const { assert(idx < length); return ptr[idx]; } }; #endif extern "C" void hello(_d_dynamicArray< const char > arg); ``` And the D compiler can generate templates in the mangled name, as this D code is translated to C++: ```d class Foo(T) {} extern (C++) void hello2(Foo!char arg2) { } ``` ```c++ // Automatically generated by LDC Compiler #pragma once #include #include #include #include #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE #else /// Represents a D [] array template struct _d_dynamicArray final { size_t length; T *ptr; _d_dynamicArray() : length(0), ptr(NULL) { } _d_dynamicArray(size_t length_in, T *ptr_in) : length(length_in), ptr(ptr_in) { } T& operator[](const size_t idx) { assert(idx < length); return ptr[idx]; } const T& operator[](const size_t idx) const { assert(idx < length); return ptr[idx]; } }; #endif template class Foo; extern void hello2(Foo* arg2); ```
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote: On Saturday, 4 November 2023 at 10:08:20 UTC, Imperatorn wrote: On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote: I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++. Can you provide an example of exactly what you want to do? ```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h` We can just assume what you're doing on the C++-side. Are you using std::string? You could try as a pointer + length and it might work, but without seeing your complete code it's quite hard to know what you want to do.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote: On Saturday, 4 November 2023 at 10:08:20 UTC, Imperatorn wrote: On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote: I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++. Can you provide an example of exactly what you want to do? ```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h` So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. So you could see that D strings are possibly built on the architecture of C strings. In C++, string is a complex standard template library that generates complex symbols and cannot be mapped as it is based on a standard library implementation.
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 10:08:20 UTC, Imperatorn wrote: On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote: I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++. Can you provide an example of exactly what you want to do? ```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`
Re: Why can't we use strings in C++ methods?
On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote: I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++. Can you provide an example of exactly what you want to do?
Why can't we use strings in C++ methods?
I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.