January 28, 2015
On 1/27/2015 2:05 PM, Rainer Schuetze wrote:
>
>
> On 26.01.2015 23:24, Walter Bright wrote:
>>> 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.
>>
>> exporting a template and then having the user instantiate outside of
>> the library doesn't make a whole lot of sense, because the
>> instantiation won't be there in the library. The library will have to
>> instantiate every use case. If the compiler knows the library
>> instantiated it, it won't re-instantiate it locally.
>
> The problem is not about into which binary the template is generated to (this
> must be the binary where it is used),

The example had marked the template itself as 'export'. This raises the specter of which binary the template instantiation exists in.

> but how to access private non-templated methods called by the template.
>
>  From the core.time.FracSec example:
>
> export struct FracSec
> {
>      ///...
>      static FracSec from(string units)(long value)
>          if(units == "msecs" ||
>             units == "usecs" ||
>             units == "hnsecs" ||
>             units == "nsecs")
>      {
>          immutable hnsecs = cast(int)convert!(units, "hnsecs")(value);
>          _enforceValid(hnsecs);
>          return FracSec(hnsecs);
>      }
>
>      private static void _enforceValid(int hnsecs)
>      {
>          if(!_valid(hnsecs))
>              throw new TimeException("FracSec must ...");
>      }
>      ///...
> }
>
> _enforceValid() could also be a free function. It is likely to be compiled into
> druntime.dll, but needs to be exported from the DLL to be callable by the
> instantiation of the template function in another DLL. The "private" forbids
> exporting, though.

I tend to view a DLL's exports as being inherently not private, hence D's export design being a "super" public. At the risk of sounding flip, I suggest simply removing the 'private' from free functions one wishes to export. If the user is calling undocumented functions that start with '_', we can presume they know what they're doing.

If you still want to hide the free function, it can be done like this:

  struct Bar(T) {
    void callit() { Impl.freefunc(); }
  }

  private struct Impl {
        export static void freefunc() { }
  }

January 28, 2015
My 5 cents:

1) "export all" approach is extremely limiting and I'd like to see it go on Linux too. One of major problems with it is that many forms of link-time optimizations (such as --gc-sections) become simply impossible when compiler can't know what symbols are actually supposed to be available externally.

2) first proposed solution does not allow to mark private functions as "export". It implicitly exports those if they are needed for actual public/export template function to work. This is not the same - those functions still can't be called via provide .di binding, it simply keeps them available for linking.

3) there is a big maintenance benefit from encouraging people to explicitly mark their API, template or not. It is a clear sign "this is a part of my libraries you are expected to use directly" and that was what my idea for attribute inference abused.
January 28, 2015
On Wednesday, 28 January 2015 at 11:01:09 UTC, Walter Bright wrote:

> The example had marked the template itself as 'export'. This raises the specter of which binary the template instantiation exists in.
>

The export in this context actually means "export all instanciations of this template". And this is needed to avoid using -allinst everywhere.
January 28, 2015
On Wednesday, 28 January 2015 at 11:01:09 UTC, Walter Bright wrote:
>
> The example had marked the template itself as 'export'. This raises the specter of which binary the template instantiation exists in.
>

Also sorry for the harsh answer, this was a classical double misunderstanding.
January 28, 2015
On Wednesday, 28 January 2015 at 11:42:19 UTC, Dicebot wrote:
>
> 2) first proposed solution does not allow to mark private functions as "export". It implicitly exports those if they are needed for actual public/export template function to work. This is not the same - those functions still can't be called via provide .di binding, it simply keeps them available for linking.

So you would prefer to keep symbols private and just make them available for linking? Or what exactly is the message here?

>
> 3) there is a big maintenance benefit from encouraging people to explicitly mark their API, template or not. It is a clear sign "this is a part of my libraries you are expected to use directly" and that was what my idea for attribute inference abused.

Agree here. Especially if you want to keep your shared library backwards compatible, so that people can simply drop in the new binary. To do that you need very fine control over what is exported and what is not.
January 28, 2015
On Wednesday, 28 January 2015 at 13:30:17 UTC, Benjamin Thaut wrote:
> On Wednesday, 28 January 2015 at 11:42:19 UTC, Dicebot wrote:
>>
>> 2) first proposed solution does not allow to mark private functions as "export". It implicitly exports those if they are needed for actual public/export template function to work. This is not the same - those functions still can't be called via provide .di binding, it simply keeps them available for linking.
>
> So you would prefer to keep symbols private and just make them available for linking? Or what exactly is the message here?

Isn't that what your first proposed solution is about? That was my understanding and I liked that understanding :) To be 100% clear :

export void foo(T : int)(T x)
{
    bar(x);
}

private void bar(int x) { }

I'd expect `bar` to be exported into resulting binary so that it can be linked against by any users of `foo` but for any attempt to call `bar` directly from D code to fail because of protection violation. If someone wants to circumvent protection by forging mangling - shooting own feet is allowed.
January 28, 2015
On Wednesday, 28 January 2015 at 13:48:45 UTC, Dicebot wrote:
>
> Isn't that what your first proposed solution is about? That was my understanding and I liked that understanding :) To be 100% clear :
>
> export void foo(T : int)(T x)
> {
>     bar(x);
> }
>
> private void bar(int x) { }
>
> I'd expect `bar` to be exported into resulting binary so that it can be linked against by any users of `foo` but for any attempt to call `bar` directly from D code to fail because of protection violation. If someone wants to circumvent protection by forging mangling - shooting own feet is allowed.

Well this would be ultimate goal. Although it is not possible to automatically detect that bar needs to be exported because that would mean you would have to analyze all possible instantiations of the template foo. (static if...)
So Automatically detecting that bar needs to be exported is not possible. We either have to make export into an attribute or use the solution where bar is actually nested into a struct which is exported instead. This is also described in my initial post with examples.
January 28, 2015
On Wednesday, 28 January 2015 at 14:16:03 UTC, Benjamin Thaut wrote:
> Well this would be ultimate goal. Although it is not possible to automatically detect that bar needs to be exported because that would mean you would have to analyze all possible instantiations of the template foo. (static if...)
> So Automatically detecting that bar needs to be exported is not possible. We either have to make export into an attribute or use the solution where bar is actually nested into a struct which is exported instead. This is also described in my initial post with examples.

Yes, I see the problem now. "static if" isn't even the worst offender, any kind of string mixins that generate the call to `bar` are impossible to detect without having actual `foo` instance. Sorry for misinterpretation.

With that in mind second option is starting to look more attractive despite the grammar change - forcing good chunk template API into structs does not sound very convenient :(
January 28, 2015
On Wednesday, 28 January 2015 at 14:31:54 UTC, Dicebot wrote:

>
> Yes, I see the problem now. "static if" isn't even the worst offender, any kind of string mixins that generate the call to `bar` are impossible to detect without having actual `foo` instance. Sorry for misinterpretation.
>
> With that in mind second option is starting to look more attractive despite the grammar change - forcing good chunk template API into structs does not sound very convenient :(

Well and then there is the third option Walter proposed:
- Make everything export even if it means that it gets callable by the user directly.
January 28, 2015
On Wednesday, 28 January 2015 at 15:01:30 UTC, Benjamin Thaut wrote:
>> With that in mind second option is starting to look more attractive despite the grammar change - forcing good chunk template API into structs does not sound very convenient :(
>
> Well and then there is the third option Walter proposed:
> - Make everything export even if it means that it gets callable by the user directly.

It is hardly a good option - I consider LTO/WPO a very important future goal for any native language.