January 29, 2015
On 1/28/2015 5:19 AM, Benjamin Thaut wrote:
> 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.

The problem is what happens when the client side instantiates the template, which it must in order to use it.
January 29, 2015
On 1/28/2015 5:27 AM, Benjamin Thaut wrote:
> Also sorry for the harsh answer, this was a classical double misunderstanding.

No problemo.
January 29, 2015
On Thursday, 29 January 2015 at 10:21:25 UTC, Walter Bright wrote:
> On 1/28/2015 5:19 AM, Benjamin Thaut wrote:
>> 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.
>
> The problem is what happens when the client side instantiates the template, which it must in order to use it.

Well if there already is a statically known instanciation it will not instanciate it. (I didn't change that behvaior). The question is what happens when you have something like this:

module a:
struct SomeTemplate(T){}
alias knownInstance = SomeTemplate!int;

module b:
SomeTemplate!int var1; // will use instanciation from a (unless -allinst)
SomeTemplate!float var2; // will instanciate
alias knownInstance2 = SomeTemplate!uint;

module c:
SomeTemplate!uint var3; // will this use instaction from b? Or instanciate itself?

I don't know enough about D's template implementation to answer the question regarding c.var3. Depending on the answer to this question I can answer what should happen if a export marked template is instanciated outside of its module. (e.g. by the user)

Please also correct me if any of the above assumptions are incorrect.
January 30, 2015
On Thursday, 29 January 2015 at 13:24:36 UTC, Benjamin Thaut wrote:
> module c:
> SomeTemplate!uint var3; // will this use instaction from b? Or instanciate itself?

That's the first instantiation with uint. If you mean float, then it will instatiate the template when compiled individually and use b's instantiation when b and c are compiled together.
January 30, 2015
Am 30.01.2015 um 11:39 schrieb Martin Nowak:
>
> If you mean float, then it
> will instatiate the template when compiled individually and use b's
> instantiation when b and c are compiled together.

If this is true, then please explain this behavior:

module a; // --> a.dll

struct Storage(T)
{
  T var;
  __gshared T s_var;
}


module b; // --> b.dll
import a;

export __gshared Storage!int g_var1;


module c; // --> c.exe
import a;
import b;

__gshared Storage!int g_var2;

void main(string[] args)
{
  g_var1.var = 2;
  g_var2.var = 3;

  g_var1.s_var = 2;
  g_var2.s_var = 3;
}

c.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_D1a14__T7StorageTiZ7Storage5s_vari" in Funktion "_Dmain".


If your statement would be true module c should not use the instance from module b because they are not compiled together. But as you can clearly see from the linker error message module c does not instanciate the template, because if module c would instanciate the template there would not be a unresolved symbol.

Compiling module c with "-allinst" solves the problem. Putting "export" in front of struct Storage(T) also solves the problem. And thats exactly the reason why it is neccessary to be able to export templates. (Where export means, export all template instanciations)
January 30, 2015
On Tuesday, 20 January 2015 at 12:23:32 UTC, Benjamin Thaut wrote:
> 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()
> {
>
> }

Clearly the better solution.
Export and protection have something in common but are not identical.
January 31, 2015
On Friday, 30 January 2015 at 19:10:06 UTC, Martin Nowak wrote:
> On Tuesday, 20 January 2015 at 12:23:32 UTC, Benjamin Thaut wrote:
>> 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()
>> {
>>
>> }
>
> Clearly the better solution.
> Export and protection have something in common but are not identical.

It has a serious drawback of increasing attribute noise even more though. First approach allows for more automatic inference.

But with D restrictions it seems the least bad option.
January 31, 2015
Am 31.01.2015 um 06:11 schrieb Dicebot:
> On Friday, 30 January 2015 at 19:10:06 UTC, Martin Nowak wrote:
>
> It has a serious drawback of increasing attribute noise even more
> though. First approach allows for more automatic inference.
>
> But with D restrictions it seems the least bad option.

Well, export is going to remain transitive. So the first approach is still going to work. The only difference is going to be that you can "force export" private declarations. So for most modules it is hopefully going to be enough to put "export { }"  around the public part of the module and force export some of the needed private declarations. For a module without templates a single "export { }" should be enough.
January 31, 2015
On Saturday, 31 January 2015 at 09:25:10 UTC, Benjamin Thaut wrote:
> Well, export is going to remain transitive. So the first approach is still going to work. The only difference is going to be that you can "force export" private declarations. So for most modules it is hopefully going to be enough to put "export { }"  around the public part of the module and force export some of the needed private declarations. For a module without templates a single "export { }" should be enough.

That's probably how it should behave, though an attribute applying only to public members unless explicitly added is unprecedented. Still seems like the right choice here, but might require some additional compiler logic.
January 31, 2015
Am 31.01.2015 um 13:07 schrieb Martin Nowak:
>
> That's probably how it should behave, though an attribute applying only
> to public members unless explicitly added is unprecedented. Still seems
> like the right choice here, but might require some additional compiler
> logic.

Well you don't have to implement it that way with in the compiler. The only thing that matters is, that the users sees this transitive behavior of export. It is not neccessary that the attribute actually gets applied recursivly within the compiler implementation. Only the export behavior needs to be implemented recursivly and I already did a implementation for that. It currently works for the export protection level and would be trivial to adapt for a export attribute. It would also not require any additional logic for applying attributes recursivly under certain conditions.

@Walter:
Making export a attribute seems to be the preferred choice in this discussion. Additionaly this was the result of the last discussion around export, a year ago, although for different reasons. The last Discussion resulted in DIP 45 which also proposes making export an attribute. Before I start with the implementation, would you be ok with making export an attribute or would you veto it?

Kind Regards
Benjamin Thaut