October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to DoctorCaptain | Am 16.10.2013 10:40, schrieb DoctorCaptain: > On Wednesday, 16 October 2013 at 06:09:48 UTC, Benjamin Thaut wrote: >> 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. > > 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. 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. > > 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 |
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | 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 |
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to DoctorCaptain | 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 |
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | Am 16.10.2013 16:08, schrieb Benjamin Thaut: > 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. > > 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 Thaut |
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Wednesday, 16 October 2013 at 14:08:52 UTC, Benjamin Thaut wrote:
> 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.
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.
|
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Wednesday, 16 October 2013 at 18:47:25 UTC, Benjamin Thaut wrote:
> Am 16.10.2013 16:08, schrieb Benjamin Thaut:
>> 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.
>>
>>
>
> 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
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!
|
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to DoctorCaptain | > 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.
|
October 16, 2013 Re: Problem: Cannot create class out of nothing using witchcraft | ||||
---|---|---|---|---|
| ||||
Posted in reply to DoctorCaptain | Am 16.10.2013 21:02, schrieb DoctorCaptain:
> On Wednesday, 16 October 2013 at 14:08:52 UTC, Benjamin Thaut wrote:
>> 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.
>
> 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.
I never had type theory in university, but your explanation sounds reasonable and correct ;-)
Kind Regards
Benjamin Thaut
|
Copyright © 1999-2021 by the D Language Foundation