digitalmars.D.learn - Problem: Cannot create class out of nothing using witchcraft
- DoctorCaptain (167/167) Oct 15 2013 dmd v2.063.2
- Benjamin Thaut (6/173) Oct 15 2013 If I move the alias declarations of WorstChild and MiddleChild outside
- Benjamin Thaut (4/4) Oct 15 2013 Your going way to complicated by actually passing the variadic arguments...
- DoctorCaptain (76/81) Oct 15 2013 Thank you for your responses!
- DoctorCaptain (4/31) Oct 15 2013 http://dpaste.dzfl.pl/ff8a5b9d
- DoctorCaptain (20/20) Oct 15 2013 I missed an extremely critical point. The working example with
- DoctorCaptain (70/70) Oct 15 2013 I've gotten extremely close. The DPaste link that follows
- Benjamin Thaut (6/9) Oct 15 2013 So is there any reason why you still pass the variadic arguments to the
- DoctorCaptain (60/72) Oct 16 2013 I suppose I was trying to give the class individual data members,
- Benjamin Thaut (25/90) Oct 16 2013 No problem, I can understand that you want to stick with your solution.
- Benjamin Thaut (6/6) Oct 16 2013 Oh something I forgot. You should really start littering your code with
- Benjamin Thaut (6/10) Oct 16 2013 There is actually a easier way to instanciate the elements. Just do "new...
- Benjamin Thaut (10/19) Oct 16 2013 I'm actually wrong. "new T[i]()" will not work because the compiler will...
- DoctorCaptain (11/33) Oct 16 2013 AWW you posted that while I was writing my latest novel. So T[i]
- DoctorCaptain (4/13) Oct 16 2013 And I could have SWORN I tried to write something like what you
- DoctorCaptain (62/73) Oct 16 2013 Thank you again for your excellent answers. I knew I shouldn't
- Benjamin Thaut (5/72) Oct 16 2013 I never had type theory in university, but your explanation sounds
- Artur Skawina (30/33) Oct 15 2013
dmd v2.063.2 Hi there! I'm terribly hopeful that you're more interested in the problem at hand than my choice of title. I've been using D for a while as my language of choice for various projects here and there, and I've recently discovered that template programming is magic. This is good. As part of the process of finding anything magic that also works, I've been going completely overboard with it. This involves, among other things, creating empty classes using templates and mixins at compile time, to build an inheritance hierarchy to do fancy things. This is all essentially irrelevant, but brings us to my issue. The next logical step in my adventure here was to see if I could create classes that weren't empty, but in fact has data members, generated at compile time using variadic templates. The first run-through went super well, and I was able to create classes with arbitrary primitive data types. However, ultimately I wanted these compile-time-generated classes with arbitrary data members to have data members that were of the type of the other classes that were also generated at compile time. That is to say, I want to generate, at compile time, classes like this: class MyClass { crazyTemplate!("MagicClassOne").MagicClassOne t1; crazyTemplate2!("MagicClassTwo").MagicClassTwo t2; } such that crazyTemplate and crazyTemplate2 each generate a class definition at compile time, accessible as defined by the string parameter. For example: template crazyTemplate(string classname) { mixin(`class ` ~ className ~ ` {}`); } The bare class-generating templates work, and generating classes that have arbitrary members at compile time using variadic templates given an arbitrary list of basic types works, but as soon as I try to use these template-generated classes as the types of the members of this variadic template, things go awry. I feel like what I'm trying to explain is a bit difficult to parse without a minimal working example, so here is one: code ------------- import std.stdio; import std.typetuple; import std.traits; import std.conv; class BaseClass {} template ChildT(string className) { mixin(`class ` ~ className ~ ` : BaseClass {}`); } template isChildOrBaseClass(T) { enum bool isChildOrBaseClass = is(T : BaseClass); } template GrabBagT(string className, T...) if (allSatisfy!(isChildOrBaseClass, T)) { mixin(genClassStr!(T)(className)); } string genClassStr(T...)(string className) { string classStr = ""; classStr ~= `static class ` ~ className ~ ` : BaseClass`; classStr ~= `{`; // Demonstrate that the template itself is not the problem classStr ~= ` ChildT!("BestChild").BestChild t1000;`; // Add arbitrary data members foreach (i, TI; T) { // Neither of these work with the generated classes, but the first // will work if GrabBagT is called with primitive types and its // constraint is commented out //classStr ~= fullyQualifiedName!(TI) ~ ` t` ~ to!(string)(i) ~ `;`; //classStr ~= __traits(identifier, TI) ~ ` t` ~ to!(string)(i) ~ `;`; } classStr ~= ` void printAttempts() {`; foreach (i, TI; T) { classStr ~= ` writeln(` ~ to!string(i) ~ `);`; } classStr ~= ` }`; classStr ~= `}`; return classStr; } int main(string[] args) { alias ChildT!("WorstChild").WorstChild WorstChild; alias ChildT!("MiddleChild").MiddleChild MiddleChild; auto magicObject = new GrabBagT!( "MagicClass", WorstChild, MiddleChild).MagicClass(); //auto magicObject = new GrabBagT!( // "MagicClass", int, float).MagicClass(); magicObject.printAttempts(); return 0; } ------------- That should compile and print out "0" and "1". Note the template constraint that bars the template instantiator from trying to instantiate GrabBagT with anything other than types that can be implicitly treated as type BaseClass. I tried using __traits(identifier) and fullyQualifiedName to get the actual type of the alias passed in (like the BestChild declaration), but the latter gives a mangled name, and the former gives just whatever the bare alias was. In any case. If the fullyQualifiedName line is uncommented, the error is: ------------ classAttributeGen.d(22): Error: undefined identifier '__T6ChildTVAyaa10_576f7273744368696c64Z' classAttributeGen.d(22): Error: classAttributeGen.__T6ChildTVAyaa10_576f7273744368696c64Z.WorstChild is used as a type classAttributeGen.d(22): Error: undefined identifier '__T6ChildTVAyaa11_4d6964646c654368696c64Z' classAttributeGen.d(22): Error: classAttributeGen.__T6ChildTVAyaa11_4d6964646c654368696c64Z.MiddleChild is used as a type classAttributeGen.d(54): Error: template instance classAttributeGen.GrabBagT!("MagicClass", WorstChild, MiddleChild) error instantiating ------------ If the __traits line is uncommented instead, the error is: ------------ classAttributeGen.d(22): Error: undefined identifier WorstChild classAttributeGen.d(22): Error: undefined identifier MiddleChild classAttributeGen.d(54): Error: template instance classAttributeGen.GrabBagT!("MagicClass", WorstChild, MiddleChild) error instantiating ------------ Of particular note is that we are giving the class a ChildT!("BestChild").BestChild member, which shows that simply using the empty-class-generating-templates is not the problem, but rather the way the type tuple is fed in to the variadic template. If the GrabBagT constraint is commented out, the uncommented magicObject instantiation is commented, the commented magicObject instantiation is uncommented, and the fullyQualifiedName line is uncommented, then this will also compile, demonstrating that a tuple of primitive data types can be used to generate classes at compile time with arbitrary, primitive data members. Ultimately, the problem I am trying to solve is generating class definitions at compile time with arbitrary, templated data members. If this is the wrong way to do it, by all means point me in the right direction. However, as an exercise to the community, is it even possible to do it the way I'm attempting here? Is it possible to do at all? Is there something awful about how templates are passed around that makes it fundamentally impossible to get their underlying type information, like with the working BestClass member, if they're passed in as template type parameters? If what I am asking is unclear, I will be more than happy to explain in a different way. I tried to be simultaneously as succinct and as comprehensive as possible with what the issue is. I also tried to find the answer to this problem, as I have with every other problem I've faced with D, through an exhaustive search of the various resources available to us, but alas I could find nothing. Of course, this is a fairly esoteric scenario, so that's entirely acceptable. That said, ideally the definitive answer can be found in future searches by finding this post. With a quiet but definitive stepping-aside to the inquiry of "What why are you doing this."
Oct 15 2013
Am 15.10.2013 10:03, schrieb DoctorCaptain:dmd v2.063.2 Hi there! I'm terribly hopeful that you're more interested in the problem at hand than my choice of title. I've been using D for a while as my language of choice for various projects here and there, and I've recently discovered that template programming is magic. This is good. As part of the process of finding anything magic that also works, I've been going completely overboard with it. This involves, among other things, creating empty classes using templates and mixins at compile time, to build an inheritance hierarchy to do fancy things. This is all essentially irrelevant, but brings us to my issue. The next logical step in my adventure here was to see if I could create classes that weren't empty, but in fact has data members, generated at compile time using variadic templates. The first run-through went super well, and I was able to create classes with arbitrary primitive data types. However, ultimately I wanted these compile-time-generated classes with arbitrary data members to have data members that were of the type of the other classes that were also generated at compile time. That is to say, I want to generate, at compile time, classes like this: class MyClass { crazyTemplate!("MagicClassOne").MagicClassOne t1; crazyTemplate2!("MagicClassTwo").MagicClassTwo t2; } such that crazyTemplate and crazyTemplate2 each generate a class definition at compile time, accessible as defined by the string parameter. For example: template crazyTemplate(string classname) { mixin(`class ` ~ className ~ ` {}`); } The bare class-generating templates work, and generating classes that have arbitrary members at compile time using variadic templates given an arbitrary list of basic types works, but as soon as I try to use these template-generated classes as the types of the members of this variadic template, things go awry. I feel like what I'm trying to explain is a bit difficult to parse without a minimal working example, so here is one: code ------------- import std.stdio; import std.typetuple; import std.traits; import std.conv; class BaseClass {} template ChildT(string className) { mixin(`class ` ~ className ~ ` : BaseClass {}`); } template isChildOrBaseClass(T) { enum bool isChildOrBaseClass = is(T : BaseClass); } template GrabBagT(string className, T...) if (allSatisfy!(isChildOrBaseClass, T)) { mixin(genClassStr!(T)(className)); } string genClassStr(T...)(string className) { string classStr = ""; classStr ~= `static class ` ~ className ~ ` : BaseClass`; classStr ~= `{`; // Demonstrate that the template itself is not the problem classStr ~= ` ChildT!("BestChild").BestChild t1000;`; // Add arbitrary data members foreach (i, TI; T) { // Neither of these work with the generated classes, but the first // will work if GrabBagT is called with primitive types and its // constraint is commented out //classStr ~= fullyQualifiedName!(TI) ~ ` t` ~ to!(string)(i) ~ `;`; //classStr ~= __traits(identifier, TI) ~ ` t` ~ to!(string)(i) ~ `;`; } classStr ~= ` void printAttempts() {`; foreach (i, TI; T) { classStr ~= ` writeln(` ~ to!string(i) ~ `);`; } classStr ~= ` }`; classStr ~= `}`; return classStr; } int main(string[] args) { alias ChildT!("WorstChild").WorstChild WorstChild; alias ChildT!("MiddleChild").MiddleChild MiddleChild; auto magicObject = new GrabBagT!( "MagicClass", WorstChild, MiddleChild).MagicClass(); //auto magicObject = new GrabBagT!( // "MagicClass", int, float).MagicClass(); magicObject.printAttempts(); return 0; } ------------- That should compile and print out "0" and "1". Note the template constraint that bars the template instantiator from trying to instantiate GrabBagT with anything other than types that can be implicitly treated as type BaseClass. I tried using __traits(identifier) and fullyQualifiedName to get the actual type of the alias passed in (like the BestChild declaration), but the latter gives a mangled name, and the former gives just whatever the bare alias was. In any case. If the fullyQualifiedName line is uncommented, the error is: ------------ classAttributeGen.d(22): Error: undefined identifier '__T6ChildTVAyaa10_576f7273744368696c64Z' classAttributeGen.d(22): Error: classAttributeGen.__T6ChildTVAyaa10_576f7273744368696c64Z.WorstChild is used as a type classAttributeGen.d(22): Error: undefined identifier '__T6ChildTVAyaa11_4d6964646c654368696c64Z' classAttributeGen.d(22): Error: classAttributeGen.__T6ChildTVAyaa11_4d6964646c654368696c64Z.MiddleChild is used as a type classAttributeGen.d(54): Error: template instance classAttributeGen.GrabBagT!("MagicClass", WorstChild, MiddleChild) error instantiating ------------ If the __traits line is uncommented instead, the error is: ------------ classAttributeGen.d(22): Error: undefined identifier WorstChild classAttributeGen.d(22): Error: undefined identifier MiddleChild classAttributeGen.d(54): Error: template instance classAttributeGen.GrabBagT!("MagicClass", WorstChild, MiddleChild) error instantiating ------------ Of particular note is that we are giving the class a ChildT!("BestChild").BestChild member, which shows that simply using the empty-class-generating-templates is not the problem, but rather the way the type tuple is fed in to the variadic template. If the GrabBagT constraint is commented out, the uncommented magicObject instantiation is commented, the commented magicObject instantiation is uncommented, and the fullyQualifiedName line is uncommented, then this will also compile, demonstrating that a tuple of primitive data types can be used to generate classes at compile time with arbitrary, primitive data members. Ultimately, the problem I am trying to solve is generating class definitions at compile time with arbitrary, templated data members. If this is the wrong way to do it, by all means point me in the right direction. However, as an exercise to the community, is it even possible to do it the way I'm attempting here? Is it possible to do at all? Is there something awful about how templates are passed around that makes it fundamentally impossible to get their underlying type information, like with the working BestClass member, if they're passed in as template type parameters? If what I am asking is unclear, I will be more than happy to explain in a different way. I tried to be simultaneously as succinct and as comprehensive as possible with what the issue is. I also tried to find the answer to this problem, as I have with every other problem I've faced with D, through an exhaustive search of the various resources available to us, but alas I could find nothing. Of course, this is a fairly esoteric scenario, so that's entirely acceptable. That said, ideally the definitive answer can be found in future searches by finding this post. With a quiet but definitive stepping-aside to the inquiry of "What why are you doing this."If I move the alias declarations of WorstChild and MiddleChild outside of main end then uncomment the __traits(identifier, ...) line it works. -- Kind Regards Benjamin Thaut
Oct 15 2013
Your going way to complicated by actually passing the variadic arguments to the generator function. If you don't pass the variadic arguments to the generator function its way simpler and also works ;-) http://dpaste.dzfl.pl/59e2547b
Oct 15 2013
On Tuesday, 15 October 2013 at 13:14:46 UTC, Benjamin Thaut wrote:Your going way to complicated by actually passing the variadic arguments to the generator function. If you don't pass the variadic arguments to the generator function its way simpler and also works ;-) http://dpaste.dzfl.pl/59e2547bThank you for your responses! The following is a modified version of my original post code that incorporates a bit from all the answers I received, and certainly puts me farther along than I was: http://dpaste.dzfl.pl/f7508d25 Taking Benjamin Thaut's suggestion to move the alias's into the global scope, GrabBagT now has access to the types it needs to know about, and my witchcraft abomination of a magic class works as long as everything is available in the same file. However. My original goal, going back to how I want to use this in the project I'm working on, is to define GrabBagT, and the associated templates, in a different file, such that I need only import the file and call: auto magicObject = new GrabBagT!("MagicClass", SomeTypeAlias, SomeOtherTypeAlias).MagicClass(); Which brings us back to the original problem, that passing in aliases to instantiations of templates doesn't work, because the type information is lost. I understand the fundamental issue you folks were bringing up in your posts: GrabBagT cannot possibly actually have access to the real types of the aliases it's receiving, as those types aren't available in its scope (which is why bringing the aliases originally defined within main() out into the global scope makes things work). But then this raises another fundamental issue, as I'm doing this exact thing successfully (passing aliases of template instantiations to other templates), where the only difference is the receiving templates do not have variadic parameters, and I throw the actual template parameter into the mixin itself. That is to say: If the template I am trying to instantiate IS NOT variadic, and I pass in an alias of an instantiated template, then the receiving template has all of the type information it needs. Example: dpaste.dzfl.pl/6d618af9 If the template I am trying to instantiate IS variadic, and I pass in a variadic list of aliases of instantiated templates, then the receiving template appears unable to retrieve all of the type information it needs out of each of the indexes of the variadic parameter. We get close with this next example, but the problem appears to be that it tries to create a static array of the tuple T of length i, instead of indexing into it to get the type (but if you provide an i greater than the actual length of the tuple, it complains about going out of bounds of the tuple length, meaning that it IS in fact aware that it's supposed to be indexing into a type tuple): dpaste.dzfl.pl/ff8a5b9d Given that the compilation error messages in the last DPaste refer to the mixed in code after the class definition string is generated and returned, the issue has to be in the way the type tuple is treated, itself. So, first, the template argument (variadic or otherwise) needs to be part of the STRING that is constructed and passed back to the mixin, so that it can then just naturally access GrabBagT's T type tuple parameter. This is how the non-variadic DPaste example works. Second, the variadic version seems to fail because the type tuple is not indexed correctly, to retrieve the type at that index, because it instead appears to try to make a static array of the whole tuple (which is odd because if you try to index the tuple with an index beyond its length, it suddenly knows it's a type tuple again). And to be absolutely clear, the underlying goal is to generate a class definition at runtime, which I can mix in and then instantiate, that can contain an arbitrary list of data members that are themselves generated at compile time by their own templates. I have demonstrated that it is possible to do this with a single arbitrary template instantiation in dpaste.dzfl.pl/6d618af9 , but as soon as we try to do it with type tuples, it chokes. I am not sure if this is a compiler bug or I'm just out of my mind, but again, for the sake of academic advancement, lets try to solve the problem in complete disregard of whether we should. If any part of my explanation of our current status on this problem is unclear, I would be happy to explain in an alternate way. Thank you again!
Oct 15 2013
Fixing links:If the template I am trying to instantiate IS NOT variadic, and I pass in an alias of an instantiated template, then the receiving template has all of the type information it needs. Example: dpaste.dzfl.pl/6d618af9http://dpaste.dzfl.pl/6d618af9If the template I am trying to instantiate IS variadic, and I pass in a variadic list of aliases of instantiated templates, then the receiving template appears unable to retrieve all of the type information it needs out of each of the indexes of the variadic parameter. We get close with this next example, but the problem appears to be that it tries to create a static array of the tuple T of length i, instead of indexing into it to get the type (but if you provide an i greater than the actual length of the tuple, it complains about going out of bounds of the tuple length, meaning that it IS in fact aware that it's supposed to be indexing into a type tuple): dpaste.dzfl.pl/ff8a5b9dhttp://dpaste.dzfl.pl/ff8a5b9dAnd to be absolutely clear, the underlying goal is to generate a class definition at runtime, which I can mix in and then instantiate, that can contain an arbitrary list of data members that are themselves generated at compile time by their own templates. I have demonstrated that it is possible to do this with a single arbitrary template instantiation in dpaste.dzfl.pl/6d618af9 , but as soon as we try to do it with type tuples, it chokes. I am not sure if this is a compiler bug or I'm just out of my mind, but again, for the sake of academic advancement, lets try to solve the problem in complete disregard of whether we should.http://dpaste.dzfl.pl/6d618af9
Oct 15 2013
I missed an extremely critical point. The working example with the single arbitrary template instantiation as a data member of the generated class, http://dpaste.dzfl.pl/6d618af9 , has the template instantiation aliases inside of main, meaning the alias is NOT within the scope of GrabBagT, but it is able to get all of the type information it needs from the alias being passed in. Which reaffirms to me that the problem is not about whether GrabBagT needs to be able to see what the alias refers to (clearly it can figure it out), but that once these aliases are wrapped up into a tuple passed into the variadic version of the template, it stops being able to figure it out. Either the syntax I'm using is wrong, there is a bug in the compiler, or for some reason this extremely specific scenario isn't allowed. In any case, example code that demonstrates the principle we are trying to achieve as working should be able to call magicObject.printSelf() and show that each of its arbitrary data members can call their own printSelf() methods successfully, as with the http://dpaste.dzfl.pl/6d618af9 example, but with an arbitrary list of instantiated templates, instead of just the one. Brain buster, this one.
Oct 15 2013
I've gotten extremely close. The DPaste link that follows demonstrates three different templates: The first template is capable of generating the string for and mixing in the definition of a class that has a single arbitrary argument. An object of that class is instantiated, and its printSelf() method is invoked to demonstrate that the arbitrary data member it was generated with is indeed what you would expect it to be. The magic here is fairly plain. The second template is capable of generating the string for the definition of a class that has some arbitrary number of arbitrary arguments at -compile- time, through the use of variadic template parameters. The issue with this string is that the type at T[n], where T is the variadic template parameter, is mangled at compile-time. The data-member-generating foreach loop shows the three potential ways I attempted to get at the full type information. All three have some problem with it, with typeid giving a fully mangled type, fullyQualifiedName giving a mostly mangled type, and __traits(identifier) giving just whatever the alias was that was passed in. The two other commented-out code sections in this template was an attempt to resolve the type information at the time of mixin, rather than within the string generation function, but this doesn't work. The third template demonstrates that D actually can resolve the individual types of the variadic template parameter correctly, so long as it's allowed to do this at runtime. The string printed as a result of instantiating this template shows exactly the class definition we want to be able to mix in at compile time, but this type information eludes us at compile time even though it's clearly readily available at runtime. The code referenced above is here: http://dpaste.dzfl.pl/a6feafc8 I'm not sure why DPaste is failing to compile the code, but I am compiling it with DMD v2.063.2. Also included at the bottom of the DPaste listing is the output I get when running that program, exactly as listed. With all of that said, there is a fundamental difference between how the first template and the second two templates are written. The first one, which works, resolves the T parameter during the mixin. The second two try to resolve the variadic types during class definition string generation. I am pretty convinced at this point that if this is ever going to work, the variadic template parameter type tuple needs to be resolved during the mixin, like with the first example. The how is the question. Again, I attempted to have the variadic template parameter types deduced during execution of the mixin with the two blocks of commented-out code in the second template, but I had no luck there, as I got the same errors as I did in my previous big post. So. By the first template, we know that we can generate class definitions with arbitrary data members and mix them in at compile time using aliases for templated, compile-time-mixin-generated classes, but for each new arbitrary type we want the generated class to have, we need to have a distinct template parameter for the type. By the third template, we know that we should have access to the fully qualified types in the variadic template parameter, but it at least appears to only be fully resolved at runtime (which I feel like is me misunderstanding something, but then that's also the root of our problem). By the second template, we show that trying to deduce the types within the type tuple (the variadic template parameter) during class definition string generation does not work, which leads us to believe it must be resolved while mixing in the class definition using the templated types, but that also doesn't seem to work (as noted by the failed attempts in the two commented out blocks of the second template). I feel like we're so very close to the answer, whether it's "Oh, you just have to do this" or "You're crazy, this is impossible." If only it was possible to summon Andrei. He'd know! Maybe it's some sort of a Bloody Mary thing? Andrei, Andrei, An-
Oct 15 2013
Am 16.10.2013 03:17, schrieb DoctorCaptain:I've gotten extremely close. The DPaste link that follows demonstrates three different templates: ...So is there any reason why you still pass the variadic arguments to the generator function and not do it the way I proposed in my last dpaste snippet? Even if you need the variadic arguments inside the generator for some logic you could still reference them by using the variadic arguments to the actual template.
Oct 15 2013
On Wednesday, 16 October 2013 at 06:09:48 UTC, Benjamin Thaut wrote:Am 16.10.2013 03:17, schrieb DoctorCaptain:I suppose I was trying to give the class individual data members, such that passing a tuple of (WorstChild, MiddleChild, BestChild) would result in a class definition of: class MagicClass { WorstClass t1; MiddleClass t2; BestClass t3; } However, if that is impossible (and frankly it'd be more difficult to work with than your way even if it was achieved), then I'll use your approach (actually, I'm just going to use your approach anyway. It's significantly cleaner than my horrid mess of a goal). That said, what is actually happening in your example? I reworked it a bit to demonstrate that the class has accessible members within T, that can be instantiated and accessed and whatnot. http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. What is T within the generated class definition? Is this just how tuples work? T is an "array" of three arbitrary pointers, initially null, that can be instantiated with new to create valid pointers to objects of each type at T's indexes? Like, T in the DPaste example is an array of pointers, such that: [WorstChild*, MiddleChild*, BestChild*]? Is it literally just magic like that? Actually, let me formally present a couple of ending thoughts/questions: First, allow me to apologize for trying to force a different, messy horrid mess of a goal on you, when your initial solution was majestic to begin with. Second, as I was trying to figure out just a moment ago, what -exactly- is T in the generated class definition, and why does it allow me to use it as an arbitrary container for objects of the arbitrary types I want it to contain (Read: why is it able to do exactly what I want it to be able to do? What's going on behind the scenes?)? Third, given that I am going to go with your solution (it works, it works well, and I can't seem to force my original goal to work, whether that was even a good idea to begin with at all (it wasn't)), can you think of a way to actually produce my original goal? That is, instead of a container T which I can use to access my arbitrary data members once the generated class is instantiated, is it actually even possible to generate individual data members, a la: class MagicClass { T[0] t0; T[1] t1; // ... etc } // ? You've been wildly helpful, and admirably concise. I am -extremely- interested in the answer to the second thought, and while I'm sure the answer is simple, it also seems -too- magic to actually work, and yet it does. Again, thank you to everyone who responded, and thank you Benjamin for your continued help.I've gotten extremely close. The DPaste link that follows demonstrates three different templates: ...So is there any reason why you still pass the variadic arguments to the generator function and not do it the way I proposed in my last dpaste snippet? Even if you need the variadic arguments inside the generator for some logic you could still reference them by using the variadic arguments to the actual template.
Oct 16 2013
Am 16.10.2013 10:40, schrieb DoctorCaptain:On Wednesday, 16 October 2013 at 06:09:48 UTC, Benjamin Thaut wrote:No problem, I can understand that you want to stick with your solution. But as Artur explained the template is actually not able to see the actual types directly and thats why full qualified identifier will not work.Am 16.10.2013 03:17, schrieb DoctorCaptain:I suppose I was trying to give the class individual data members, such that passing a tuple of (WorstChild, MiddleChild, BestChild) would result in a class definition of: class MagicClass { WorstClass t1; MiddleClass t2; BestClass t3; } However, if that is impossible (and frankly it'd be more difficult to work with than your way even if it was achieved), then I'll use your approach (actually, I'm just going to use your approach anyway. It's significantly cleaner than my horrid mess of a goal). That said, what is actually happening in your example? I reworked it a bit to demonstrate that the class has accessible members within T, that can be instantiated and accessed and whatnot. http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. What is T within the generated class definition? Is this just how tuples work? T is an "array" of three arbitrary pointers, initially null, that can be instantiated with new to create valid pointers to objects of each type at T's indexes? Like, T in the DPaste example is an array of pointers, such that: [WorstChild*, MiddleChild*, BestChild*]? Is it literally just magic like that? Actually, let me formally present a couple of ending thoughts/questions: First, allow me to apologize for trying to force a different, messy horrid mess of a goal on you, when your initial solution was majestic to begin with.I've gotten extremely close. The DPaste link that follows demonstrates three different templates: ...So is there any reason why you still pass the variadic arguments to the generator function and not do it the way I proposed in my last dpaste snippet? Even if you need the variadic arguments inside the generator for some logic you could still reference them by using the variadic arguments to the actual template.Second, as I was trying to figure out just a moment ago, what -exactly- is T in the generated class definition, and why does it allow me to use it as an arbitrary container for objects of the arbitrary types I want it to contain (Read: why is it able to do exactly what I want it to be able to do? What's going on behind the scenes?)?T is the variadic argument T that is passed to the actual template "GrabBagT". It might become more clear when actually copy & pasting the generated code into the template. The problem is that you try to reference the classes by name. Thats not necessary. You get the classes passed in as template arguments. So you just reference them as template arguments instead of referencing them by name. It is possible to do so by not generating access via the name but instead use the template arguments passed to GrabBagT. I hope this made it a bit more clear. I might have some more time later today to look into your new examples and modify them.Third, given that I am going to go with your solution (it works, it works well, and I can't seem to force my original goal to work, whether that was even a good idea to begin with at all (it wasn't)), can you think of a way to actually produce my original goal? That is, instead of a container T which I can use to access my arbitrary data members once the generated class is instantiated, is it actually even possible to generate individual data members, a la: class MagicClass { T[0] t0; T[1] t1; // ... etc } // ?What do you need individual data members for? In my example the "T members" is actually a instance of a tuple which actually comes down to the exakt same data layout like individual data members. The only difference is that you access them by index and not by name. Which is actually a plus if you ask me for generic programming. You can even get back the tuple by doing typeof(members);You've been wildly helpful, and admirably concise. I am -extremely- interested in the answer to the second thought, and while I'm sure the answer is simple, it also seems -too- magic to actually work, and yet it does. Again, thank you to everyone who responded, and thank you Benjamin for your continued help.No problem. I love the metaprogramming abilities of D and a occansional challenge is always welcome ;-) -- Kind Regards Benjamin Thaut
Oct 16 2013
Oh something I forgot. You should really start littering your code with pragma(msg, ...) statements to better understand what it does. You can for example make your generator output "pramga(msg, T.stringof);" to find out what T actually is. Kind Regards Benjamin Thaut
Oct 16 2013
Am 16.10.2013 10:40, schrieb DoctorCaptain:http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic.There is actually a easier way to instanciate the elements. Just do "new T[i]();" no need for typeof. -- Kind Regards Benjamin Thaut
Oct 16 2013
Am 16.10.2013 16:08, schrieb Benjamin Thaut:Am 16.10.2013 10:40, schrieb DoctorCaptain:I'm actually wrong. "new T[i]()" will not work because the compiler will think it is a array allocation. You actually have to use new typeof(member[i])(); I created a example which generates individual class members for each of the arguments bassed to GrabBagT: http://dpaste.dzfl.pl/eef2edec -- Kind Regards Benjamin Thauthttp://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic.There is actually a easier way to instanciate the elements. Just do "new T[i]();" no need for typeof.
Oct 16 2013
On Wednesday, 16 October 2013 at 18:47:25 UTC, Benjamin Thaut wrote:Am 16.10.2013 16:08, schrieb Benjamin Thaut:AWW you posted that while I was writing my latest novel. So T[i] doesn't work? I guess I shouldn't have opened my eyes this morning. In any case, typeof() DOES work, so as long as there is a way to extract the type, we're good. I am extremely pleased it's actually possible to get individual data members like I was originally attempting to do. I'm likely not going to actually do this, as your T members; solution is cleaner, but I'm glad it's not just arbitrarily impossible. Thank you so much!Am 16.10.2013 10:40, schrieb DoctorCaptain:I'm actually wrong. "new T[i]()" will not work because the compiler will think it is a array allocation. You actually have to use new typeof(member[i])(); I created a example which generates individual class members for each of the arguments bassed to GrabBagT: http://dpaste.dzfl.pl/eef2edechttp://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic.There is actually a easier way to instanciate the elements. Just do "new T[i]();" no need for typeof.
Oct 16 2013
AWW you posted that while I was writing my latest novel. So T[i] doesn't work? I guess I shouldn't have opened my eyes this morning. In any case, typeof() DOES work, so as long as there is a way to extract the type, we're good. I am extremely pleased it's actually possible to get individual data members like I was originally attempting to do. I'm likely not going to actually do this, as your T members; solution is cleaner, but I'm glad it's not just arbitrarily impossible. Thank you so much!And I could have SWORN I tried to write something like what you have in your latest DPaste, but I must have been doing something wrong, of course. In any case, I'm glad this whole thing has been so very cleanly resolved. Infinity thank you.
Oct 16 2013
On Wednesday, 16 October 2013 at 14:08:52 UTC, Benjamin Thaut wrote:Am 16.10.2013 10:40, schrieb DoctorCaptain:Thank you again for your excellent answers. I knew I shouldn't have posted my most recent response at two in the morning or whatever it was; when I woke up this morning I was thinking, "I understand everything I was confused about last night, and I'm going to look silly to the fellas that answer my questions." Especially, pretty much the first thing I thought of when I opened my eyes this morning was "I don't need to do typeof, I can index the type tuple, and now I look silly." I definitely knew that the T in the mixed-in class definition is the same as the variadic template parameter T in our GrabBagT template. My question, at the time, was geared towards, "How in the world does it act like a tuple of types that we can just use?" The answer to that is, painfully obviously, T is literally a tuple of types that we can just use, working exactly as intended. Hopefully the following is correct, as an exercise in making sure that my understanding is correct: Purely theoretically speaking (as in we're no longer talking about D specifically, but rather "type theory" in general), let's take the type int[]. Variables of type int[] can be created. Let's do this: int[] iarray; For some within-bounds index i, iarray[i] will yield a -value- whose -type- is int. Along these same lines (again in a go-with-me-here, theoretical sense), if we were to "index" the actual type int[], like int[i], then what is yielded at that index is the -type- int. int[] is a homogenous type tuple of some length, containing only the -type- int as an element at each of its indexes. Go with me here. This works perfectly well. At compile time, the compiler knows everything it needs to know about int[] in order to reason about how a variable of that type, like iarray, can behave. It knows that at every within-bounds index of iarray, it can be sure to find a value of type int, because int[] is a homogenous type tuple of the type int. In exactly this same way, T is also a type tuple. The only difference is, T can be (but by no means has to be) a heterogenous type tuple. That is, since we're instantiating these templates (that take T...) at compile time, all types contained within T are known at compile time, and can be reasoned about. So let's say we declare something like: T members; instantiated such that myTemplate(T...) is called like myTemplate!(int, float, bool) This means that, while at int[0] we can expect the -type- int, and at int[1] we can still expect the -type- int, at T[0] we expect the -type- int, at T[1] we expect the -type- float, and at T[2] we expect the -type- bool. So, at members[0], we can store a -value- of type int, at members[1] we can store a -value- of type float, and at members[2], we can store a -value- of type bool. The reason this is possible is because the compiler is aware of all of the types, and their order, in the type tuple T at compile time. The compiler can reason about the behavior of any index within members, because it can map that index within members back to the same index within T. As long as members[n] is treated as the type T[n], the compiler can reason about the behavior of a heterogenous "array" members, of type T. Correct? And again again again, thank you for your help.http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic.There is actually a easier way to instanciate the elements. Just do "new T[i]();" no need for typeof.
Oct 16 2013
Am 16.10.2013 21:02, schrieb DoctorCaptain:On Wednesday, 16 October 2013 at 14:08:52 UTC, Benjamin Thaut wrote:I never had type theory in university, but your explanation sounds reasonable and correct ;-) Kind Regards Benjamin ThautAm 16.10.2013 10:40, schrieb DoctorCaptain:Thank you again for your excellent answers. I knew I shouldn't have posted my most recent response at two in the morning or whatever it was; when I woke up this morning I was thinking, "I understand everything I was confused about last night, and I'm going to look silly to the fellas that answer my questions." Especially, pretty much the first thing I thought of when I opened my eyes this morning was "I don't need to do typeof, I can index the type tuple, and now I look silly." I definitely knew that the T in the mixed-in class definition is the same as the variadic template parameter T in our GrabBagT template. My question, at the time, was geared towards, "How in the world does it act like a tuple of types that we can just use?" The answer to that is, painfully obviously, T is literally a tuple of types that we can just use, working exactly as intended. Hopefully the following is correct, as an exercise in making sure that my understanding is correct: Purely theoretically speaking (as in we're no longer talking about D specifically, but rather "type theory" in general), let's take the type int[]. Variables of type int[] can be created. Let's do this: int[] iarray; For some within-bounds index i, iarray[i] will yield a -value- whose -type- is int. Along these same lines (again in a go-with-me-here, theoretical sense), if we were to "index" the actual type int[], like int[i], then what is yielded at that index is the -type- int. int[] is a homogenous type tuple of some length, containing only the -type- int as an element at each of its indexes. Go with me here. This works perfectly well. At compile time, the compiler knows everything it needs to know about int[] in order to reason about how a variable of that type, like iarray, can behave. It knows that at every within-bounds index of iarray, it can be sure to find a value of type int, because int[] is a homogenous type tuple of the type int. In exactly this same way, T is also a type tuple. The only difference is, T can be (but by no means has to be) a heterogenous type tuple. That is, since we're instantiating these templates (that take T...) at compile time, all types contained within T are known at compile time, and can be reasoned about. So let's say we declare something like: T members; instantiated such that myTemplate(T...) is called like myTemplate!(int, float, bool) This means that, while at int[0] we can expect the -type- int, and at int[1] we can still expect the -type- int, at T[0] we expect the -type- int, at T[1] we expect the -type- float, and at T[2] we expect the -type- bool. So, at members[0], we can store a -value- of type int, at members[1] we can store a -value- of type float, and at members[2], we can store a -value- of type bool. The reason this is possible is because the compiler is aware of all of the types, and their order, in the type tuple T at compile time. The compiler can reason about the behavior of any index within members, because it can map that index within members back to the same index within T. As long as members[n] is treated as the type T[n], the compiler can reason about the behavior of a heterogenous "array" members, of type T. Correct? And again again again, thank you for your help.http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic.There is actually a easier way to instanciate the elements. Just do "new T[i]();" no need for typeof.
Oct 16 2013
On 10/15/13 10:03, DoctorCaptain wrote:If what I am asking is unclear, I will be more than happy to explain in a different way. I tried to be simultaneously as succinct and as comprehensive as possible with what the issue is.I'm not sure what exactly you're trying to do, but... The issue is just that you are trying to access types that are not available inside the GrabBagT template. With /built-in/ types this of course works, as 'int' etc are always known. One way to deal with that would be: template GrabBagT(string className, T...) if (allSatisfy!(isChildOrBaseClass, T)) { mixin(genClassStr!(T.length)(className)); } string genClassStr(size_t TL)(string className) { string classStr = ""; classStr ~= `static class ` ~ className ~ ` : BaseClass`; classStr ~= `{`; // Demonstrate that the template itself is not the problem classStr ~= ` ChildT!("BestChild").BestChild t1000;`; // Add arbitrary data members foreach (i; 0..TL) classStr ~= "T["~ to!(string)(i) ~ `] t` ~ to!(string)(i) ~ `;`; classStr ~= ` void printAttempts() {`; foreach (i; 0..TL) classStr ~= ` writeln(` ~ to!string(i) ~ `);`; classStr ~= ` }`; classStr ~= `}`; return classStr; } artur
Oct 15 2013