I'm currently working on Windows DLL support which has stronger rules
than linux shared objects for which symbols actually get exported from a
shared library. But as we want to replicate the same behaviour on linux
using symbol visibility (e.g. gcc 4 -fVisibility=hidden) this issue also
applies to linux once implemented.
Currently export means two things:
- the symbol is publicy accessible (same as public)
- the symbol will be accisble across shared library boundaries
This has the following issue:
export void templateFunc(T)()
{
someHelperFunc();
}
private void someHelperFunc()
{
}
And you don't even have to go into phobos to hit this problem. It is
already in druntime see core.time.FracSec._enforceValid
This works with the current linux shared objects because they simply
export all symbols. But once only symbols with export get exported this
breaks.
The problem here is that you don't want to make someHelperFunc() export
because that would mean users could call it directly, but you want it to
be available for cross shared library calls. The cross shared library
call happens if a template is instanced from a different shared library
/ executable than the module it was originally located in.
There are two solutions for this.
1) Given that export is transitive (that means if a struct or class is
declared export every member that is _not_ private will be accessible
across shared library boundaries. This behaviour is required to make the
export protection level work on windows)
You can now do the following:
export struct SomeStruct
{
static public void templateFunc(T)()
{
someHelperFunc();
}
static package void someHelperFunc()
{
}
}
Because of the transitivity someHelperFunc will be exported but still
not be callable by the user directly. This can be used to fix the issue
in core.time but may not be so well suited if you want the template to
be on module level instead of nesting it into a struct.
2) Make export an attribute. If export is no longer an protection level
but instead an attribute this issue can easily be solved by doing.
export public void templateFunc(T)()
{
someHelperFunc();
}
export private void someHelperFunc()
{
}
But this would require grammar changes. Which are generally avoided if
possible.
There would be a third option, which I rather avoid. Doing a
"pramga(forceExport)" or something like that.
My implementation, which I ran into this issue with, currently usses
approach 1. What do you think how this sould be solved?
Walter: What was the general idea behind export when you designed it,
and how can it be used to solve this problem?
Kind Regards
Benjamin Thaut