www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - const(Class) is mangled as Class const* const

reply Benjamin Thaut <code benjamin-thaut.de> writes:
Consider the following C++ and D source:

class Class
{
	virtual ~Class(){}
};

// mangles as ?getClass  YAPEAVClass  XZ
Class * getClass() { return nullptr; }

// mangles as ?getClassConst  YAPEBVClass  XZ
const Class * getClassConst() { return nullptr; }

// mangles as ?getClassConstConst  YAQEBVClass  XZ
const Class * const getClassConstConst() { return nullptr; }

extern(C++)
{
   class Class
   {
     void _cppDtor() {}
   }

   // Mangles as ?getClass  YAPEAVClass  XZ
   Class getClass() {return null;}

   // Mangles as ?getClassConst  YAQEBVClass  XZ
   const(Class) getClassConst() {return null;}
}

As you see from the above example D mangles the getClassConst as 
a "Class const * const" instead of a "Class const *" ("YAQEBV" vs 
"YAPEBV"). Is this expected behavior? The core problem is that D 
can not express one of the two. Either const(Class) becomes 
"Class const *" or "Class const * const". I've never seen C++ 
code that returns const pointers to const classes so I think the 
default should be "Class const *". Either way its rather bad that 
we can only represent one or the other. Sooner or later someone 
will hit this problem again wanting the other option or both. Any 
idea how we can avoid changing C++ source code in order to bind 
it to D? Using pragma(mangle,) works but is kind of ugly. 
Especially because the string to pragma(mangle,) can't be 
genearted using CTFE.

Should I open a bug for this?
Mar 26 2017
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Sunday, 26 March 2017 at 10:43:11 UTC, Benjamin Thaut wrote:
 As you see from the above example D mangles the getClassConst 
 as a "Class const * const" instead of a "Class const *" 
 ("YAQEBV" vs "YAPEBV"). Is this expected behavior?
It's consistent. D's const is transitive, and D doesn't allow you to specify const on the indirection of a reference type. So there is no problem on the C++ mangling side of things, but, arguably, there is one in D's sementic, that isn't new. Something like differentiating "const(C) i" and "const C i" may be a good idea.
Mar 26 2017
next sibling parent reply Namespace <rswhite4 gmail.com> writes:
On Sunday, 26 March 2017 at 14:30:00 UTC, deadalnix wrote:
 On Sunday, 26 March 2017 at 10:43:11 UTC, Benjamin Thaut wrote:
 As you see from the above example D mangles the getClassConst 
 as a "Class const * const" instead of a "Class const *" 
 ("YAQEBV" vs "YAPEBV"). Is this expected behavior?
It's consistent. D's const is transitive, and D doesn't allow you to specify const on the indirection of a reference type. So there is no problem on the C++ mangling side of things, but, arguably, there is one in D's sementic, that isn't new. Something like differentiating "const(C) i" and "const C i" may be a good idea.
After reading your post, I wonder: How could I translate the following C++ code to D? ---- int a = 2; int* const p = &a; ----
Mar 26 2017
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sunday, March 26, 2017 14:51:28 Namespace via Digitalmars-d wrote:
 On Sunday, 26 March 2017 at 14:30:00 UTC, deadalnix wrote:
 On Sunday, 26 March 2017 at 10:43:11 UTC, Benjamin Thaut wrote:
 As you see from the above example D mangles the getClassConst
 as a "Class const * const" instead of a "Class const *"
 ("YAQEBV" vs "YAPEBV"). Is this expected behavior?
It's consistent. D's const is transitive, and D doesn't allow you to specify const on the indirection of a reference type. So there is no problem on the C++ mangling side of things, but, arguably, there is one in D's sementic, that isn't new. Something like differentiating "const(C) i" and "const C i" may be a good idea.
After reading your post, I wonder: How could I translate the following C++ code to D? ---- int a = 2; int* const p = &a; ----
You don't. Once part of a type is const, everything inside it is const. So, if a pointer is const, everything it points to is const. You can have the outer part be mutable with the inner part be const, but not the other way around. D's const can do tail-const, but it can't do head-const. Now, while you can't use const to make the pointer const and what it points to mutable, you _can_ make the the pointer read-only while still having what it points to be fully mutable by putting it in a struct which restricts write-access to the pointer. I believe that that's essentially what std.experimental.typecons.Final is supposed to do. Personally, I don't think that the fact that you can't use const for head-const in D is really a loss, since it's almost never what you want. Tail-const is _way_ more useful. But it is true that by making D's const fully transitive, there are variations of constness that C++ can do that D can't. immutable pretty much forces that though, and it does simplify the language. - Jonathan M Davis
Mar 26 2017
parent reply Jerry <hurricane hereiam.com> writes:
On Sunday, 26 March 2017 at 15:29:02 UTC, Jonathan M Davis wrote:
 Personally, I don't think that the fact that you can't use 
 const for head-const in D is really a loss, since it's almost 
 never what you want. Tail-const is _way_ more useful. But it is 
 true that by making D's const fully transitive, there are 
 variations of constness that C++ can do that D can't. immutable 
 pretty much forces that though, and it does simplify the 
 language.
There are quite a few things wrong with const, it's so bad phobos isn't even const-correct when it should be. In cmp() for example, if you pass a lambda that takes the parameters by reference. You will be modifying temporary values that cmp() created on the stack. These should be const, but then what if it is a pointer? It is a different situation and you don't really want const cause you are going to be modifying the correct struct (the one pointed to). It is just easier to not use const in D cause it makes your code more difficult to actually use. That's exactly what Phobos does, it ignores const for the most part because it is easier not to use it.
Mar 26 2017
parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sunday, March 26, 2017 18:31:52 Jerry via Digitalmars-d wrote:
 On Sunday, 26 March 2017 at 15:29:02 UTC, Jonathan M Davis wrote:
 Personally, I don't think that the fact that you can't use
 const for head-const in D is really a loss, since it's almost
 never what you want. Tail-const is _way_ more useful. But it is
 true that by making D's const fully transitive, there are
 variations of constness that C++ can do that D can't. immutable
 pretty much forces that though, and it does simplify the
 language.
There are quite a few things wrong with const, it's so bad phobos isn't even const-correct when it should be. In cmp() for example, if you pass a lambda that takes the parameters by reference. You will be modifying temporary values that cmp() created on the stack. These should be const, but then what if it is a pointer? It is a different situation and you don't really want const cause you are going to be modifying the correct struct (the one pointed to). It is just easier to not use const in D cause it makes your code more difficult to actually use. That's exactly what Phobos does, it ignores const for the most part because it is easier not to use it.
There are significant pros and cons when comparing C++ and D's const, but they usually relate to the ability to get around const in C++ and the lack of ability to do so in D. The ability to create a const pointer to a mutable element is occasionally something that someone wants to do, but in my experience, it's pretty useless. I'm not sure that I've ever used it in C++ (and I've programmed professinally primarily in C++), and when I was learning Java and found out that that's what Java's final did, I decided that all it was good for was constants of built-in types, and I think that that's mostly what I've seen other folks do with it. Having a pointer/reference that can't change while what it points to can just isn't very useful. It's having a mutable pointer to const that's useful. Now, as for const in D in general and how it compares to C++, that's a rather difficult question and highly debatable (and it's been debated here on many occasions). C++'s const is little more than documentation. It prevents accidental mutation, but there are so many ways around it that it's borderline meaningless. It only works as well as it does, because it's a convention that programmers _usually_ hold to. But it gurantees almost nothing. For instance, it's perfectly possible to have a class where all of its members are const but where all of them mutate the state of the object. The fact that that doesn't normally happen is simply because fortunately, programmers normally choose to behave themselves with mutable and casting away const. But they don't have to, and the compiler doesn't enforce it. D's const, on the other hand, has strong guarantees about something that's const never being mutated unless something elsewhere in the code has access to a mutable reference and changes the data that way. The const reference is never able to change the data without violating the type system. So, D's const actually means something. It provides real guarantees. But the reality of the matter is that that's so restrictive that pretty quickly you simply can't use const. There are too many idioms that require backdoors to const - mutexes, memory management, lazy initializaiton, etc. So, the end result is that in C++, you don't have much in the way of guarantees, but you're able to use what you do have all over the place. Accidental mutation is prevented and programmer intention is conveyed, but not much of anything is really guaranteed. Whereas with D, you have the strong guarantees, and you can use const in certain circumstances, but you're quickly forced to use it in only very restricted circumstances - especially if user-defined types or templates are involved. Too much simply doesn't work with true const. What most code really needs is logical const, and the compiler can't guarantee that. As to whether C++ or D did a better job with const, I really don't know. I find C++'s const to be pretty terrible from the standpoint of what it really protects, and I only recall one time in my entire programming career that it's actually caught a bug for me, but it's still nice to be able to indicate that a function doesn't mutate its arguments, even if it's not actually guaranteed, since it's usually true. The fact that D's const provides the stronger guarantees is fantastic, but it's also so restrictive that it borders on useless. So, ultimately, I'm not very happy with either solution, and I don't know what the best one would be. Arguably, immutable is what's truly useful - though obviously, code has to be written with it in mind, because a lot of code won't work with it without that - but for it to do its job, D's const pretty much has to be the way it is. Even if we wanted C++'s const in D, we couldn't have it unless it didn't interoperate with immutable. And as for the C++ concept of "const-correctness", I think that the end result of all of this is that it really doesn't apply to D. When code is const-correct, that essentially means that it will compile with const and that it's theoretically, "logically" const - _not_ that it's actually const. It's about convention and conveying the intention of the programmer, not actually guaranteeing anything. And D's const is all about guarantees. For better or worse, I think anyone thinking about const-correctness with D code is almost certainly thinking about const the wrong way in D. And yes, the end result of all of this is that templated code can almost never use const. So, a _lot_ of Phobos doesn't use it. And on some level, that sucks, but I'm not sure that we'd really be any better off with C++'s const either. There are pros and cons both ways. - Jonathan M Davis
Mar 26 2017
prev sibling parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
On Sunday, 26 March 2017 at 14:30:00 UTC, deadalnix wrote:
 It's consistent. D's const is transitive, and D doesn't allow 
 you to specify const on the indirection of a reference type. So 
 there is no problem on the C++ mangling side of things, but, 
 arguably, there is one in D's sementic, that isn't new.
I disagree. When binding C++ code to D I don't care about D's const rules. I care about the C++ const rules. There are thousands of C++ libraries out there that can't be bound to D because they use const Class* instead of const Class* const. So in my eyes there is definitly something wrong with the C++ mangling of D.
Mar 26 2017
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Sunday, 26 March 2017 at 17:41:57 UTC, Benjamin Thaut wrote:
 On Sunday, 26 March 2017 at 14:30:00 UTC, deadalnix wrote:
 It's consistent. D's const is transitive, and D doesn't allow 
 you to specify const on the indirection of a reference type. 
 So there is no problem on the C++ mangling side of things, 
 but, arguably, there is one in D's sementic, that isn't new.
I disagree. When binding C++ code to D I don't care about D's const rules. I care about the C++ const rules. There are thousands of C++ libraries out there that can't be bound to D because they use const Class* instead of const Class* const. So in my eyes there is definitly something wrong with the C++ mangling of D.
It is clear that you won't be able to express 100% of C++ in D, that would require to important all the weird parts of C++ into D, but if we are doing so, why use D in the first place ? Note that using const Class* in C++ is essentially useless. The class remains mutable and the reference is local the the callee anyway, so it doesn't change anything for the caller. Such a pattern is most likely indicative of a bug on the C++ side, or at least of code that do not do what the author intend to.
Mar 26 2017
next sibling parent reply Jerry <hurricane hereiam.com> writes:
On Sunday, 26 March 2017 at 22:29:56 UTC, deadalnix wrote:
 It is clear that you won't be able to express 100% of C++ in D, 
 that would require to important all the weird parts of C++ into 
 D, but if we are doing so, why use D in the first place ?

 Note that using const Class* in C++ is essentially useless. The 
 class remains mutable and the reference is local the the callee 
 anyway, so it doesn't change anything for the caller. Such a 
 pattern is most likely indicative of a bug on the C++ side, or 
 at least of code that do not do what the author intend to.
For `const Class*` the Class is not mutable. It is the case of `Class* const` that Class is mutable. I see a lot of people in D say similar things about it. Saying it is a bug, saying it's a good thing that a const pointer with mutable type isn't in D. Yet they always tend to be the people that have never actually used C++. As is indicative of not even knowing the correct syntax to use in C++. A common matter in C++ is to use templates, you may have seen it, it's a really common pattern, `const T&`. The magic that makes this work is that you read it like this: `T const &`. They both mean the samething but I find makes more sense, conceptually to read it like that. Now substitute a type for T, `int* const &`. You see here that int is mutable for this template. You can see my other post about cmp(), and how Phobos avoids usages of const as it just makes writing generic code difficult.
Mar 26 2017
parent deadalnix <deadalnix gmail.com> writes:
On Sunday, 26 March 2017 at 22:56:59 UTC, Jerry wrote:
 On Sunday, 26 March 2017 at 22:29:56 UTC, deadalnix wrote:
 It is clear that you won't be able to express 100% of C++ in 
 D, that would require to important all the weird parts of C++ 
 into D, but if we are doing so, why use D in the first place ?

 Note that using const Class* in C++ is essentially useless. 
 The class remains mutable and the reference is local the the 
 callee anyway, so it doesn't change anything for the caller. 
 Such a pattern is most likely indicative of a bug on the C++ 
 side, or at least of code that do not do what the author 
 intend to.
For `const Class*` the Class is not mutable. It is the case of `Class* const` that Class is mutable.
You are correct. See my first post for an explanation of this specific case.
Mar 27 2017
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/26/2017 3:29 PM, deadalnix wrote:
 Note that using const Class* in C++ is essentially useless. The class remains
 mutable and the reference is local the the callee anyway, so it doesn't change
 anything for the caller. Such a pattern is most likely indicative of a bug on
 the C++ side, or at least of code that do not do what the author intend to.
Ironically, because C++ const is not transitive, most programmers use const in C++ as if it was transitive. This is most evident in templates where: const T is used.
Mar 27 2017
prev sibling parent kinke <noone nowhere.com> writes:
On Sunday, 26 March 2017 at 17:41:57 UTC, Benjamin Thaut wrote:
 There are thousands of C++ libraries out there that can't be 
 bound to D because they use const Class* instead of const 
 Class* const. So in my eyes there is definitly something wrong 
 with the C++ mangling of D.
I agree that C++-mangling a const D object reference as `const T *const` isn't helpful although it would be consistent with D semantics. As deadalnix pointed out, the const for the pointer itself only concerns the callee and not the caller. I sometimes use `void foo(const T *bla); ... void foo(const T *const bla) { ... }` if I find it useful to make clear that `bla` won't change in my foo() implementation, but I never use the second const in the function declaration in the header as it's just useless clutter for the caller. Having said that, you can only declare a C++ type as D class if it's exclusively passed and returned as pointer (at least in the parts you are going to interface with via D). This was true for the C++-based DMD front-end and would also be true for some types used in LLVM. But as soon as you want to interface with a C++ function taking an object as `[const] T&`, afaik you're f*cked and need to declare it as D struct. So I'm quite skeptical that I'll often be able to use D classes to represent C++ types.
Mar 27 2017
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/26/2017 3:43 AM, Benjamin Thaut wrote:
 Should I open a bug for this?
It's not a bug, it was intended that way. The trouble is that D cannot express a <const pointer> to <mutable>. Whichever way it is mangled will gore someone's ox. D went with the simplest mangling solution, which is to mangle all C++ const pointers as "head const". The obvious solution is to implement "head const" in D, but that is a major change to the type system and the philosophy of D. I suggest a simpler way - declare the C++ side of the D interface in a way that matches the way D mangles it. It's always been true that in order to interface D with C++ you'll need to be a bit flexible on the C++ side.
Mar 27 2017
parent reply kinke <noone nowhere.com> writes:
On Monday, 27 March 2017 at 20:09:35 UTC, Walter Bright wrote:
 Whichever way it is mangled will gore someone's ox. D went with 
 the simplest mangling solution, which is to mangle all C++ 
 const pointers as "head const".
 [...]
 I suggest a simpler way - declare the C++ side of the D 
 interface in a way that matches the way D mangles it. It's 
 always been true that in order to interface D with C++ you'll 
 need to be a bit flexible on the C++ side.
Unfortunately, it's almost always the other way around - D code trying to interop with one of the gazillions existing C++ libs, and nobody wants to maintain his own fork with D-compatible glue interfaces. How often did you use `const T *const` vs. `const T *` in your C++ headers? ;) I think this would be a tiny change for D, breaking almost no code and well worth the reduction in required 'flexibility on the C++ side'.
Mar 27 2017
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/27/2017 1:41 PM, kinke wrote:
 Unfortunately, it's almost always the other way around - D code trying to
 interop with one of the gazillions existing C++ libs, and nobody wants to
 maintain his own fork with D-compatible glue interfaces. How often did you use
 `const T *const` vs. `const T *` in your C++ headers? ;) I think this would be
a
 tiny change for D, breaking almost no code and well worth the reduction in
 required 'flexibility on the C++ side'.
It's made to work with: const T which is the norm with C++ templates.
Mar 27 2017
parent reply kinke <noone nowhere.com> writes:
On Monday, 27 March 2017 at 22:04:55 UTC, Walter Bright wrote:
 On 3/27/2017 1:41 PM, kinke wrote:
 Unfortunately, it's almost always the other way around - D 
 code trying to
 interop with one of the gazillions existing C++ libs, and 
 nobody wants to
 maintain his own fork with D-compatible glue interfaces. How 
 often did you use
 `const T *const` vs. `const T *` in your C++ headers? ;) I 
 think this would be a
 tiny change for D, breaking almost no code and well worth the 
 reduction in
 required 'flexibility on the C++ side'.
It's made to work with: const T which is the norm with C++ templates.
Okay, so how exactly do I bind D code to a C++ header-only-template library? I thought that in that case you need a full D translation anyway...
Mar 27 2017
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/27/2017 3:12 PM, kinke wrote:
 It's made to work with:

    const T

 which is the norm with C++ templates.
Okay, so how exactly do I bind D code to a C++ header-only-template library? I thought that in that case you need a full D translation anyway...
C++ templates are always header-only. I don't really understand your question.
Mar 27 2017
parent reply kinke <noone nowhere.com> writes:
On Monday, 27 March 2017 at 22:24:26 UTC, Walter Bright wrote:
 On 3/27/2017 3:12 PM, kinke wrote:
 It's made to work with:

    const T

 which is the norm with C++ templates.
Okay, so how exactly do I bind D code to a C++ header-only-template library? I thought that in that case you need a full D translation anyway...
C++ templates are always header-only. I don't really understand your question.
Yep, so there are no libs my D code can link to, so how am I supposed to use C++ templates from D (as you're using that as argument for the `const T *const` mangling)?
Mar 27 2017
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/27/2017 3:30 PM, kinke wrote:
 On Monday, 27 March 2017 at 22:24:26 UTC, Walter Bright wrote:
 On 3/27/2017 3:12 PM, kinke wrote:
 It's made to work with:

    const T

 which is the norm with C++ templates.
Okay, so how exactly do I bind D code to a C++ header-only-template library? I thought that in that case you need a full D translation anyway...
C++ templates are always header-only. I don't really understand your question.
Yep, so there are no libs my D code can link to, so how am I supposed to use C++ templates from D (as you're using that as argument for the `const T *const` mangling)?
There's still a miscommunication here, as header-only template libraries are not linked to.
Mar 27 2017
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-03-28 00:30, kinke wrote:

 Yep, so there are no libs my D code can link to, so how am I supposed to
 use C++ templates from D (as you're using that as argument for the
 `const T *const` mangling)?
As far as I understand, D can link with C++ templates if they're instantiated on the C++ side. It would link with the instantiated template not the actual template. -- /Jacob Carlborg
Mar 28 2017
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/28/2017 11:12 AM, Jacob Carlborg wrote:
 As far as I understand, D can link with C++ templates if they're instantiated
on
 the C++ side. It would link with the instantiated template not the actual
template.
Recall that dmd itself connected to C++ templates when the front end was not full in D.
Mar 28 2017
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Monday, March 27, 2017 20:41:51 kinke via Digitalmars-d wrote:
 On Monday, 27 March 2017 at 20:09:35 UTC, Walter Bright wrote:
 Whichever way it is mangled will gore someone's ox. D went with
 the simplest mangling solution, which is to mangle all C++
 const pointers as "head const".
 [...]
 I suggest a simpler way - declare the C++ side of the D
 interface in a way that matches the way D mangles it. It's
 always been true that in order to interface D with C++ you'll
 need to be a bit flexible on the C++ side.
Unfortunately, it's almost always the other way around - D code trying to interop with one of the gazillions existing C++ libs, and nobody wants to maintain his own fork with D-compatible glue interfaces. How often did you use `const T *const` vs. `const T *` in your C++ headers? ;) I think this would be a tiny change for D, breaking almost no code and well worth the reduction in required 'flexibility on the C++ side'.
Realistically, unless D fully supports C++ (which pretty much means that it has to become C++ on some level), you're almost always going to be stuck with some sort of glue layer between D code and C++ code. There's no reasonable way around that. We can work to improve the situation so that more C++ stuff just works when hooking up to D, but we'll never get all the way there, because that would mean dragging C++ into D, which we really don't want. There was talk at one point of trying to declare some sort of extern(C++) const that worked more like C++'s const, but even just that would be a huge mess and would further complicate the already overly complicated situation with const in D. And for that matter, even though D is highly compatible with C code, you still have to worry about maintaining all of the bindings. So, even then, you're still basically dealing with a glue layer to maintain, even if it's just there to tell D about the symbols in C land rather than adding any real code. Any time that D interacts with another language, _someone_ is going to have to maintain some sort of glue layer, even if it's a very thin layer, and to a great extent, I think that eliminating that layer is a pipe dream, though I do agree that improvements to make it thinner would certainly be nice (assuming that the cost isn't too high). Now, as for this particular case with const, I really don't know what should be done. What's currently done _is_ the most correct, but it's also something that really isn't what would be done normally in C++ - at least not outside of templated code. Pointers to const are _very_ prevalent, but const pointers to const really aren't. But I'd also be worried about what quirks and problems we'd end up with if we tried to mangle extern(C++)'s const with semantics that didn't match D's semantics, even if in most cases, it wouldn't matter. Also, in general, unless a C++ function was written to be called from D, I don't know how likely it is to work very well. It definitely _can_ work, but from what I've seen thus far, you tend to need to create C++ wrappers to interact with D code anyway, and if you do that, you just write the C++ functions with the correct constness, and it's no longer a problem. - Jonathan M Davis
Mar 27 2017
parent reply kinke <noone nowhere.com> writes:
On Tuesday, 28 March 2017 at 02:14:25 UTC, Jonathan M Davis wrote:
 Realistically, unless D fully supports C++ (which pretty much 
 means that it has to become C++ on some level), you're almost 
 always going to be stuck with some sort of glue layer between D 
 code and C++ code. There's no reasonable way around that. We 
 can work to improve the situation so that more C++ stuff just 
 works when hooking up to D, but we'll never get all the way 
 there, because that would mean dragging C++ into D, which we 
 really don't want.
I know that. I'm just arguing for this tiny change in C++-mangling of D const object references as a remedy for this one particular issue out of many wrt. C++ interop. What I don't get is why it's considered important to have a matching C++ mangling for templates across D and C++ - what for? I only care about mangling wrt. interop if I wanna link to some foreign code, and with templates I can't, so I see absolutely no problem with a D template `extern (C++) void foo()(const(Object) arg)` being mangled slightly differently (arg as `const Object*`) than a C++ template `template <typename T> void foo(const T arg)` with `T = const Object*` (arg as `const Object* const`). Don't get me wrong, I don't advocate C++-mangling a D `const(S*)` for some struct S as `const S*` at all - we're talking specifically about D class references here, which don't have a direct C++ analogon, so choosing to C++-mangle them in a special way sounds absolutely feasible to me.
Mar 28 2017
parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 28 March 2017 at 08:30:43 UTC, kinke wrote:
 What I don't get is why it's considered important to have a 
 matching C++ mangling for templates across D and C++ - what 
 for? I only care about mangling wrt.
If you still think this is a mangling problem, please reread my first response in this thread.
Mar 28 2017
parent reply kinke <noone nowhere.com> writes:
On Tuesday, 28 March 2017 at 12:55:02 UTC, deadalnix wrote:
 On Tuesday, 28 March 2017 at 08:30:43 UTC, kinke wrote:
 What I don't get is why it's considered important to have a 
 matching C++ mangling for templates across D and C++ - what 
 for? I only care about mangling wrt.
If you still think this is a mangling problem, please reread my first response in this thread.
You don't seem to get my point, I don't know why it's apparently that hard. I don't want to be able to express both `const T* const` AND `const T*` in C++, I only want D's const(Object) mangling to express solely the former instead of the latter, as there's no use for the double-const, except maybe for templates as Walter pointed out, but there's no template interop between D and C++ anyway. I absolutely don't care that it's inconsistent to what a D const(Object) reference actually is (both pointer and class const) when passing such a thing BY VALUE to C++. As I said, there's no C++ analogon for D object references, so why not have it be a special case in the C++ mangler...
Mar 28 2017
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 28 March 2017 at 13:18:57 UTC, kinke wrote:
 You don't seem to get my point, I don't know why it's 
 apparently that hard.
It's hard because you assume I did not understood you point and you keep repeating the same thing. I understand you point and showed you why it isn't a mangling problem at all, and gave you direction you may want to dig in to make a proposal that may actually get traction. But you can chose to entrench yourself in a position were nobody understands your genius. You won't get any result, but depending on your personality, it may make you feel good, which is already something.
Mar 28 2017
parent kinke <noone nowhere.com> writes:
On Tuesday, 28 March 2017 at 14:11:16 UTC, deadalnix wrote:
 I understand you point and showed you why it isn't a mangling 
 problem at all, and gave you direction you may want to dig in 
 to make a proposal that may
actually get traction. If you really did get my point, it should be clear that I don't see a necessity for differentiating between `const T` and `const(T)` on the D side in general, transitive const hasn't been an issue for my D/C++ interop use cases yet, but the const(Object) issue the OP arises would definitely be a show stopper at some point and, unlike a more general solution, can be trivially remedied.
Mar 28 2017
prev sibling parent Manu <turkeyman gmail.com> writes:
On Tue, Mar 28, 2017 at 11:21 PM kinke via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On Tuesday, 28 March 2017 at 12:55:02 UTC, deadalnix wrote:
 On Tuesday, 28 March 2017 at 08:30:43 UTC, kinke wrote:
 What I don't get is why it's considered important to have a
 matching C++ mangling for templates across D and C++ - what
 for? I only care about mangling wrt.
If you still think this is a mangling problem, please reread my first response in this thread.
You don't seem to get my point, I don't know why it's apparently that hard. I don't want to be able to express both `const T* const` AND `const T*` in C++, I only want D's const(Object) mangling to express solely the former instead of the latter, as there's no use for the double-const, except maybe for templates as Walter pointed out, but there's no template interop between D and C++ anyway. I absolutely don't care that it's inconsistent to what a D const(Object) reference actually is (both pointer and class const) when passing such a thing BY VALUE to C++. As I said, there's no C++ analogon for D object references, so why not have it be a special case in the C++ mangler...
I've lost sleep on this point for many years. I keep changing my mind between purity and what's actually useful, but I've settled on what you say here. It is my opinion from a decade of experience that D should mangle const(Class) as `const Class *`. It is what you want 99% of the time. There's some precedent for this too; C++ actually strips the head const off of the types when mangling function arguments. For instance: void t(const int *); void t(const int * const); Both functions mangle to `void t(const int *)` (and this is an invalid overload). The pointer const is not present in the mangling here. We follow this rule when mangling const class arguments to functions. In this case, we strip the pointer const from the mangling (as does C++). The case where it can go either way is with templates: void foo<const Class * const>(); void foo<const Class *>(); These are valid overloads... and D can only express the former instantiation, which basically never occurs in C++. I accept that they are functionally different things, and 'correct-ness' says that we should indeed mangle the former one, but that's just not useful. I think even in the template case, we should mangle const(Class) to `const Class *`, and not `const Class * const`. It is possible to conjure an exploit where C++ may modify a const D variable across the binding, but that's extremely contrived, and the capabilities our current mangling limits us from is an endless pain in the arse.
Aug 25 2020
prev sibling parent reply Nathan S. <no.public.email example.com> writes:
On Monday, 27 March 2017 at 20:41:51 UTC, kinke wrote:
 On Monday, 27 March 2017 at 20:09:35 UTC, Walter Bright wrote:
 Whichever way it is mangled will gore someone's ox. D went 
 with the simplest mangling solution, which is to mangle all 
 C++ const pointers as "head const".
 [...]
 I suggest a simpler way - declare the C++ side of the D 
 interface in a way that matches the way D mangles it. It's 
 always been true that in order to interface D with C++ you'll 
 need to be a bit flexible on the C++ side.
Unfortunately, it's almost always the other way around - D code trying to interop with one of the gazillions existing C++ libs, and nobody wants to maintain his own fork with D-compatible glue interfaces. How often did you use `const T *const` vs. `const T *` in your C++ headers? ;) I think this would be a tiny change for D, breaking almost no code and well worth the reduction in required 'flexibility on the C++ side'.
I just ran into this problem too. Is there some way around this with pragma(mangle)? Forking the 3rd-party library would be my last resort. If there's a way that I can write the declaration in D I would prefer to do that.
Aug 25 2020
parent Nathan S. <no.public.email example.com> writes:
On Wednesday, 26 August 2020 at 00:41:18 UTC, Nathan S. wrote:
 I just ran into this problem too. Is there some way around this 
 with pragma(mangle)?
For anyone else wondering: it turns out yes, pragma(mangle) works even with virtual functions. I didn't find a convenient way of generating the mangling other than inspecting the object file and copying the mangled name by hand, but that works fine for a small number of functions.
Aug 26 2020
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/26/2017 3:43 AM, Benjamin Thaut wrote:
 Should I open a bug for this?
https://issues.dlang.org/show_bug.cgi?id=21200
Aug 26 2020