DIP22 : Private symbol visibility

Dicebot m.strashun at gmail.com
Wed Jan 30 01:29:16 PST 2013


Case 1 (binary level, C + D):

----- sample.d -----
module sample;
private int func() { return 42; }
----------

----- oops.c -----
#include <stdio.h>

extern int _D6sample4funcFZi();

void* _Dmodule_ref = 0;
void* _D15TypeInfo_Struct6__vtblZ = 0;

void _Dmain() { }

int main()
{
     long value = _D6sample4funcFZi();
     printf("%ld\n", value);
     return 0;
}
----------

----- shell -----
$ dmd - c sample.d
$ gcc -c oops.c
$ gcc oops.o sample.o
./a.out
42
----------

This is valid code now and will break. Internal linkage is a 
binary-level encapsulation tool, contrary to language-level 
private. Not that when compiling sample.d dmd can't know if 
oops.c will actually link to func and make decision about 
internal linkage. Saying this is invalid code may severely limit 
language interconnection possibilities and something like 
injecting druntime.

Case 2 (pure D, language level):

----- sample.d -----
module sample;
private struct Hest
{
     int a, b;
}
public alias Hidden UseMe;
----------

----- oops.d -----
import sample;
import std.stdio;

void main()
{
     UseMe tmp;
     tmp.a = 42;
}
----------

Now suddenly changing Test definition may break code in oops.d 
and we need first to make sure Test is not referenced in public 
aliases or as function parameter or as public type member field 
etc. Again, this code itself is not only valid but quite 
idiomatic. Internal linkage provides strong guarantees that any 
change to symbol will affect only its module, with no special 
cases.

Case 3 (consistency):

I do insist on keeping class and module protection attribute 
consistent. Saying class privates are always accessible from 
other modules via tupleof & friends and module privates may be 
not is causing confusion for no real gain. Also it may break code 
if we have any means to enumerate module symbols via traits (do 
we? I don't know).


More information about the Digitalmars-d-announce mailing list