Thread overview
Making external types available to mixins
Nov 17, 2018
John Chapman
Nov 17, 2018
Neia Neutuladh
Nov 17, 2018
Adam D. Ruppe
Nov 18, 2018
John Chapman
Nov 22, 2018
Eduard Staniloiu
Nov 23, 2018
John Chapman
Nov 22, 2018
Nicholas Wilson
Nov 23, 2018
Kagamin
Nov 24, 2018
John Chapman
November 17, 2018
The following code doesn't compile because the generated type name needs to be available inside the mixin's scope, whereas it's actually in another module.

auto makeWith(string className, Args…)(auto ref Args args) {
  mixin("return makeWith!(I", className, "Factory)(args);"); // Fowarded to implementation of makeWith below
}

auto makeWith(T, Args…)(auto ref Args args) … // This is the implementation

The idea is that users could type (for example) makeWith!`Calendar`(…) instead of the longer makeWith!ICalendarFactory(…).

I tried mixing in an import statement with the help of std.traits.moduleName so that the I...Factory type would be available but again the compiler complains that it's undefined.

Has anyone had a similar need and come up with a solution?
November 17, 2018
On Sat, 17 Nov 2018 17:58:54 +0000, John Chapman wrote:
> The idea is that users could type (for example) makeWith!`Calendar`(…)
> instead of the longer makeWith!ICalendarFactory(…).

Your project might define a hundred types named ICalendarFactory; the compiler can't figure out which one you're talking about unless you use the fully qualified name.

If you require that Calendar and ICalendarFactory be defined in the same module, you can use Calendar's module name to look up the appropriate ICalendarFactory.

You can also just build a string that the calling code mixes in.
November 17, 2018
On Saturday, 17 November 2018 at 17:58:54 UTC, John Chapman wrote:
> Has anyone had a similar need and come up with a solution?

You might be able to just pass it the Calendar type, and then fetch its parent module and get the ICalendarFactory from there (assuming they are defined in the same module).

But generally speaking, passing strings to a mixin that refer to something in another module isn't going to work well thanks to scoping rules. You are better off passing a symbol of some sort.
November 18, 2018
On Saturday, 17 November 2018 at 21:11:38 UTC, Adam D. Ruppe wrote:
> On Saturday, 17 November 2018 at 17:58:54 UTC, John Chapman wrote:
>> Has anyone had a similar need and come up with a solution?
>
> You might be able to just pass it the Calendar type, and then fetch its parent module and get the ICalendarFactory from there (assuming they are defined in the same module).
>
> But generally speaking, passing strings to a mixin that refer to something in another module isn't going to work well thanks to scoping rules. You are better off passing a symbol of some sort.

So there is no actual Calendar type. There's an ICalendarFactory type that creates instances of ICalendar (these types are part of a third-party API).  "Calendar" is just a key users could use when calling a "makeWith" method that would build the ICalendar/Factory names, instantiate the factory, call the appropriate factory method and return the result. There are thousands of such object/factory pairs in the API. Just trying to cut out a lot of boilerplate code, but it doesn't seem doable this way.
November 22, 2018
On Sunday, 18 November 2018 at 11:29:51 UTC, John Chapman wrote:
> On Saturday, 17 November 2018 at 21:11:38 UTC, Adam D. Ruppe wrote:
>> On Saturday, 17 November 2018 at 17:58:54 UTC, John Chapman wrote:
>>> Has anyone had a similar need and come up with a solution?
>>
>> You might be able to just pass it the Calendar type, and then fetch its parent module and get the ICalendarFactory from there (assuming they are defined in the same module).
>>
>> But generally speaking, passing strings to a mixin that refer to something in another module isn't going to work well thanks to scoping rules. You are better off passing a symbol of some sort.
>
> So there is no actual Calendar type. There's an ICalendarFactory type that creates instances of ICalendar (these types are part of a third-party API).  "Calendar" is just a key users could use when calling a "makeWith" method that would build the ICalendar/Factory names, instantiate the factory, call the appropriate factory method and return the result. There are thousands of such object/factory pairs in the API. Just trying to cut out a lot of boilerplate code, but it doesn't seem doable this way.

Cheers,

So I had a go at this and I have a working solution.
https://run.dlang.io/is/oaH6Ib

At first, I tried to do everything in the mixin, as you can see with the `failedAttempt` function. The idea was that this should have worked like `mixin(failedAttempt!"Calendar"(1, 2, 3));`. As you can see, and the name suggests, I wasn't able to make it work with `args`.

The solution I have to your problem is to use a template, in this case the `theType` template that will expand to the fully qualified name. So you'd use it like
`makeWith!(theType!"Calendar")(args);`

Hope it helps!

Edi
November 22, 2018
On Saturday, 17 November 2018 at 17:58:54 UTC, John Chapman wrote:
> The following code doesn't compile because the generated type name needs to be available inside the mixin's scope, whereas it's actually in another module.
>
> auto makeWith(string className, Args…)(auto ref Args args) {
>   mixin("return makeWith!(I", className, "Factory)(args);"); // Fowarded to implementation of makeWith below
> }
>
> auto makeWith(T, Args…)(auto ref Args args) … // This is the implementation
>
> The idea is that users could type (for example) makeWith!`Calendar`(…) instead of the longer makeWith!ICalendarFactory(…).
>
> I tried mixing in an import statement with the help of std.traits.moduleName so that the I...Factory type would be available but again the compiler complains that it's undefined.
>
> Has anyone had a similar need and come up with a solution?

you need to qualify the names: I use https://github.com/libmir/dcompute/blob/master/source/dcompute/driver/ocl/util.d#L77-L97
for this in dcompute (needs to be updated for the new style of mixin but you get the idea).
November 23, 2018
On Thursday, 22 November 2018 at 16:27:08 UTC, Eduard Staniloiu wrote:
> So I had a go at this and I have a working solution.
> https://run.dlang.io/is/oaH6Ib
>
> At first, I tried to do everything in the mixin, as you can see with the `failedAttempt` function. The idea was that this should have worked like `mixin(failedAttempt!"Calendar"(1, 2, 3));`. As you can see, and the name suggests, I wasn't able to make it work with `args`.
>
> The solution I have to your problem is to use a template, in this case the `theType` template that will expand to the fully qualified name. So you'd use it like
> `makeWith!(theType!"Calendar")(args);`
>
> Hope it helps!
>
> Edi

Thanks!
November 23, 2018
On Saturday, 17 November 2018 at 17:58:54 UTC, John Chapman wrote:
> The following code doesn't compile because the generated type name needs to be available inside the mixin's scope, whereas it's actually in another module.
>
> auto makeWith(string className, Args…)(auto ref Args args) {
>   mixin("return makeWith!(I", className, "Factory)(args);"); // Fowarded to implementation of makeWith below
> }
>
> auto makeWith(T, Args…)(auto ref Args args) … // This is the implementation
>
> The idea is that users could type (for example) makeWith!`Calendar`(…) instead of the longer makeWith!ICalendarFactory(…).

Well, just have all factories in one module and import it, then they will be visible.

import allfactories;
auto makeWith(string className, Args…)(auto ref Args args) {
  mixin("return makeWith!(I", className, "Factory)(args);"); // Fowarded to implementation of makeWith below
}

Or predeclare make functions in factory modules

interface ICalendarFactory
{
  ...
}

alias makeCalendar=makeWith!ICalendarFactory;
November 24, 2018
On Friday, 23 November 2018 at 21:49:55 UTC, Kagamin wrote:
> Well, just have all factories in one module and import it, then they will be visible.

They're part of another library over which I have no control, but yes, I could still import them all and make life easier.

> import allfactories;
> auto makeWith(string className, Args…)(auto ref Args args) {
>   mixin("return makeWith!(I", className, "Factory)(args);"); // Fowarded to implementation of makeWith below
> }
>
> Or predeclare make functions in factory modules
>
> interface ICalendarFactory
> {
>   ...
> }
>
> alias makeCalendar=makeWith!ICalendarFactory;