www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Making external types available to mixins

reply John Chapman <johnch_atms hotmail.com> writes:
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?
Nov 17 2018
next sibling parent Neia Neutuladh <neia ikeran.org> writes:
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.
Nov 17 2018
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.
Nov 17 2018
parent reply John Chapman <johnch_atms hotmail.com> writes:
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.
Nov 18 2018
parent reply Eduard Staniloiu <edi33416 gmail.com> writes:
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
Nov 22 2018
parent John Chapman <johnch_atms hotmail.com> writes:
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!
Nov 23 2018
prev sibling next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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).
Nov 22 2018
prev sibling parent reply Kagamin <spam here.lot> writes:
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;
Nov 23 2018
parent John Chapman <johnch_atms hotmail.com> writes:
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;
Nov 24 2018