Head Const

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 16 07:43:49 PST 2016


On Tuesday, 16 February 2016 at 06:04:42 UTC, Jonathan M Davis 
wrote:
> On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright 
> wrote:
>> rears its head again :-)
>>
>> Head Const is what C++ has for const, i.e. it is not 
>> transitive, applies to one level only. D has transitive const.
>>
> In this particular case, doesn't this really just come down to 
> mangling? It's undefined behavior in D to mutate a const object 
> (even if it was constructed as mutable), so we can't just slap 
> D const on C++ types and have that work, since the C++ code 
> could legally mutate the object. But since C++ considers it 
> defined behavior to mutate a const object by casting away const 
> (or at least it does in all but some very specific cases), can 
> we just get away with the D code treating D const as mutable? 
> If so, then it's purely a matter of mangling. And for that, we 
> could do something like add @cppconst or cppconst that the 
> compiler recognizes and which is only valid in extern(C++) 
> declarations. It would unfortunately have to be more than a 
> simple attribute, because it would have to apply to parts of a 
> parameter's type like C++'s const does (instead of the whole 
> type at once), but if it were implemented such that it was just 
> something that went on the extern(C++) function parameter types 
> (or return types) for mangling purposes, and the D code just 
> treated it as mutable, then it would at least restrict the muck 
> to extern(C++).

Actually, one could argue that the fact that we support const at 
all with other languages - even with C - is broken in that C/C++ 
code can cast away our const and mutate the variable we passed 
in, breaking our type system. We rely on the programmer to know 
that the C/C++ code isn't going to do that, and most of the time, 
you really have no clue. You just assume that it won't - and it 
probably won't, but you don't know for sure.

So, most of the time, it will work just fine, but const with 
extern(C) and extern(C++) really does not provide the guarantees 
that const is supposed to provide.

Of course, there's also the issue that with extern(C) and 
extern(C++), everything is really __gshared, and yet we typically 
treat  it like it's thread-local just like the D code is. 
Arguably, all parameters and return types with extern(C) and 
extern(C++) should be automatically treated as shared, and not 
doing so is risking a world of pain if the C/C++ code misbehaves, 
but having them be treated as shared would be really annoying to 
deal with, and most C/C++ code that's being called probably isn't 
doing anything with threads that could violate D's guarantees 
about thread-local variables (just like most C/C++ code 
presumably isn't casting away const and mutating when we pass it 
something from D) - but there's no guarantee that it isn't.

So, as far as compiler guarantees and the type system go, 
extern(C) and extern(C++) are a bit of a disaster, much as they 
generally work in practice. But I don't know what we can really 
do about that other than trying to educate people about the risks 
and possibly have the compiler avoid certain types of 
optimizations around extern(C) and extern(C++) code (which it may 
already do).

- Jonathan M Davis


More information about the Digitalmars-d mailing list