digitalmars.D.learn - typedef behavior
- Alex (33/33) Feb 09 2018 A question about Typedef usage:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (7/40) Feb 09 2018 You must have meant
- Alex (9/62) Feb 09 2018 Yup. They are shared by two Typedef instantiations with different
- =?UTF-8?Q?Ali_=c3=87ehreli?= (6/19) Feb 09 2018 I think this is a limitation of Typedef.
- Alex (14/28) Feb 09 2018 Ah... From your hint I arrived at the following:
- Alex (6/15) Feb 09 2018 Hmm... No. As the arrays are shared all of them will be
- Alex (3/3) Feb 10 2018 On Saturday, 10 February 2018 at 02:55:26 UTC, Alex wrote:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (16/19) Feb 11 2018 Basically, Typedef looks like this:
- Alex (19/34) Feb 11 2018 In the same way as it is handled by this:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (15/55) Feb 12 2018 I agree that'd be nice. Sadly, it's not a reasonable expectation.
- Alex (6/20) Feb 12 2018 But isn't foo scoped somehow?
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (6/22) Feb 12 2018 Not really, since D doesn't have a concept of an address
- Alex (3/8) Feb 12 2018 Ok... so the query on ptr on a static is not to be allowed? And
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (46/56) Feb 12 2018 I'm sorry, I was apparently unclear. When I said 'static array'
- Alex (38/83) Feb 12 2018 /*
A question about Typedef usage: Say, I have the following circumstances /// --- code --- /// import std.typecons; void main() { MyEA ea; MyEB eb; ea.tarr.length = 5; static assert(!is(MyEA == MyEB)); static assert(!is(MyEA == E)); static assert(!is(MyEB == E)); assert(ea.tarr.length == eb.tarr.length); // line 11 assert(ea.tarr.length != eb.tarr.length); // line 12 } struct T { size_t i; } struct E { size_t i; static T[] tarr; } alias MyEA = Typedef!(E, E.init, "A"); // line 26 alias MyEB = Typedef!(E, E.init, "B"); // line 27 /// --- code ends --- /// Line 12 yields an assertion error, while line 11 does not. This tells me, that despite the fact the types MyEA and MyEB are different they still share the static array, which would contradict the definition of static. I suppose, the tricky thing is to tweak the init property of the typedefs in lines 26/27 to avoid this clash. How to manage this?
Feb 09 2018
On 02/09/2018 03:45 PM, Alex wrote:A question about Typedef usage: Say, I have the following circumstances /// --- code --- /// import std.typecons; void main() { MyEA ea; MyEB eb; ea.tarr.length = 5; static assert(!is(MyEA == MyEB)); static assert(!is(MyEA == E)); static assert(!is(MyEB == E)); assert(ea.tarr.length == eb.tarr.length); // line 11 assert(ea.tarr.length != eb.tarr.length); // line 12You must have meant assert(ea.tarr.ptr != eb.tarr.ptr); // line 12 Indeed, .ptr are unexpectedly the same.} struct T { size_t i; } struct E { size_t i; static T[] tarr;To save time to others, note that 'tarr' is a static member that ends up being shared by two Typedef instantiations.} alias MyEA = Typedef!(E, E.init, "A"); // line 26 alias MyEB = Typedef!(E, E.init, "B"); // line 27 /// --- code ends --- /// Line 12 yields an assertion error, while line 11 does not. This tells me, that despite the fact the types MyEA and MyEB are different they still share the static array, which would contradict the definition of static. I suppose, the tricky thing is to tweak the init property of the typedefs in lines 26/27 to avoid this clash. How to manage this?Ali
Feb 09 2018
On Saturday, 10 February 2018 at 01:01:39 UTC, Ali Çehreli wrote:On 02/09/2018 03:45 PM, Alex wrote:Yes... this is a more precise comparison :)A question about Typedef usage: Say, I have the following circumstances /// --- code --- /// import std.typecons; void main() { MyEA ea; MyEB eb; ea.tarr.length = 5; static assert(!is(MyEA == MyEB)); static assert(!is(MyEA == E)); static assert(!is(MyEB == E)); assert(ea.tarr.length == eb.tarr.length); // line 11 assert(ea.tarr.length != eb.tarr.length); // line 12You must have meant assert(ea.tarr.ptr != eb.tarr.ptr); // line 12 Indeed, .ptr are unexpectedly the same.Yup. They are shared by two Typedef instantiations with different cookies. So... The question is two-fold: Would it help to alter the init value of the Typedef? If yes, how to alter it? If no, is this a bug?} struct T { size_t i; } struct E { size_t i; static T[] tarr;To save time to others, note that 'tarr' is a static member that ends up being shared by two Typedef instantiations.} alias MyEA = Typedef!(E, E.init, "A"); // line 26 alias MyEB = Typedef!(E, E.init, "B"); // line 27 /// --- code ends --- /// Line 12 yields an assertion error, while line 11 does not. This tells me, that despite the fact the types MyEA and MyEBaredifferent they still share the static array, which wouldcontradict thedefinition of static. I suppose, the tricky thing is to tweak the init property ofthetypedefs in lines 26/27 to avoid this clash. How to managethis? Ali
Feb 09 2018
On 02/09/2018 05:14 PM, Alex wrote:cookies.Yup. They are shared by two Typedef instantiations with differentstruct E { size_t i; static T[] tarr;To save time to others, note that 'tarr' is a static member that ends up being shared by two Typedef instantiations.So... The question is two-fold: Would it help to alter the init value of the Typedef? If yes, how to alter it? If no, is this a bug?I think this is a limitation of Typedef. I can't see a way out (at least one that can support any type E). It should be possible if you can modify E but I can't work something out now. Ali
Feb 09 2018
On Saturday, 10 February 2018 at 01:23:20 UTC, Ali Çehreli wrote:Ah... From your hint I arrived at the following: Inside of the struct E I define more then one static array. Namely, one for each Typedef I plan to instantiate. The Typedefs have to be known at compile time, so the amount of them has to be known by me :) Then, during the initialization, I work only with one of the arrays of E, depending on the Typedef I use. During the work inside of E, the object will have to check, which array was initialized and cooperate with this array, as this is the only possibility. As a workaround this will work, I think... Thanks! Nevertheless, I would file a bug later on... all ideas are appreciated in the meanwhile.Yup. They are shared by two Typedef instantiations withdifferent cookies.So... The question is two-fold: Would it help to alter the init value of the Typedef? If yes, how to alter it? If no, is this a bug?I think this is a limitation of Typedef. I can't see a way out (at least one that can support any type E). It should be possible if you can modify E but I can't work something out now. Ali
Feb 09 2018
On Saturday, 10 February 2018 at 02:08:50 UTC, Alex wrote:Inside of the struct E I define more then one static array. Namely, one for each Typedef I plan to instantiate. The Typedefs have to be known at compile time, so the amount of them has to be known by me :) Then, during the initialization, I work only with one of the arrays of E, depending on the Typedef I use. During the work inside of E, the object will have to check, which array was initialized and cooperate with this array, as this is the only possibility.Hmm... No. As the arrays are shared all of them will be initialized for every Typedef and the last point (decision during the work inside of a single Typedef) can not be achieved. So... there has to be another indirection, which will be filled during (possibly static) initialization.
Feb 09 2018
On Saturday, 10 February 2018 at 02:55:26 UTC, Alex wrote: bug filed https://issues.dlang.org/show_bug.cgi?id=18416
Feb 10 2018
On Sunday, 11 February 2018 at 01:32:52 UTC, Alex wrote:On Saturday, 10 February 2018 at 02:55:26 UTC, Alex wrote: bug filed https://issues.dlang.org/show_bug.cgi?id=18416Basically, Typedef looks like this: struct Typedef(T) { T _payload; // Forward method calls, member access, etc, to _payload. } If T looks like this: struct T { static int[3] arr; void foo() { arr[0]++; } } How is Typedef supposed to wrap T.foo in such a way that it uses a different arr depending on whether it's called from the Typedef or from T? -- Simen
Feb 11 2018
On Sunday, 11 February 2018 at 15:18:11 UTC, Simen Kjærås wrote:Basically, Typedef looks like this: struct Typedef(T) { T _payload; // Forward method calls, member access, etc, to _payload. } If T looks like this: struct T { static int[3] arr; void foo() { arr[0]++; } } How is Typedef supposed to wrap T.foo in such a way that it uses a different arr depending on whether it's called from the Typedef or from T? -- SimenIn the same way as it is handled by this: /// --- code --- /// void main(){} static assert(T.arr.ptr != S.arr.ptr); struct T { static int[3] arr; void foo() { arr[0]++; } } struct S { static int[3] arr; void foo() { arr[0]++; } } /// --- code ends --- /// I understand that Typedef should be kept simple. But if it defines a type which is recognized as another type in respect to the underlying one, then I should be able to rely on independence of everything, like I would copy/paste the implementation. Or do I misinterpret something?
Feb 11 2018
On Sunday, 11 February 2018 at 19:33:23 UTC, Alex wrote:On Sunday, 11 February 2018 at 15:18:11 UTC, Simen Kjærås wrote:I agree that'd be nice. Sadly, it's not a reasonable expectation. :( A more extreme example: You have a compiled library, and some .di (header) files. In one of those files is this code: struct S { static int[] arr; void foo(); } Now how should Typedef go about making foo() do the right thing? Even with compiler support, this is impossible - the source of S.foo is simply not available, and it doesn't take the address of the static data as a parameter anywhere. -- SimenBasically, Typedef looks like this: struct Typedef(T) { T _payload; // Forward method calls, member access, etc, to _payload. } If T looks like this: struct T { static int[3] arr; void foo() { arr[0]++; } } How is Typedef supposed to wrap T.foo in such a way that it uses a different arr depending on whether it's called from the Typedef or from T? -- SimenIn the same way as it is handled by this: /// --- code --- /// void main(){} static assert(T.arr.ptr != S.arr.ptr); struct T { static int[3] arr; void foo() { arr[0]++; } } struct S { static int[3] arr; void foo() { arr[0]++; } } /// --- code ends --- /// I understand that Typedef should be kept simple. But if it defines a type which is recognized as another type in respect to the underlying one, then I should be able to rely on independence of everything, like I would copy/paste the implementation. Or do I misinterpret something?
Feb 12 2018
On Monday, 12 February 2018 at 08:51:14 UTC, Simen Kjærås wrote:I agree that'd be nice. Sadly, it's not a reasonable expectation. :(:)A more extreme example: You have a compiled library, and some .di (header) files. In one of those files is this code: struct S { static int[] arr; void foo(); } Now how should Typedef go about making foo() do the right thing? Even with compiler support, this is impossible - the source of S.foo is simply not available, and it doesn't take the address of the static data as a parameter anywhere. -- SimenBut isn't foo scoped somehow? I mean, if foo is part of a type, then either you have to write s.foo, or S.foo. And if the address of a static belongs to a type, shouldn't this resolve the ambiguities?
Feb 12 2018
On Monday, 12 February 2018 at 09:10:52 UTC, Alex wrote:Not really, since D doesn't have a concept of an address associated with a type, only with instances of it. So when you use a static array, the address is hard-coded. -- SimenA more extreme example: You have a compiled library, and some .di (header) files. In one of those files is this code: struct S { static int[] arr; void foo(); } Now how should Typedef go about making foo() do the right thing? Even with compiler support, this is impossible - the source of S.foo is simply not available, and it doesn't take the address of the static data as a parameter anywhere.But isn't foo scoped somehow? I mean, if foo is part of a type, then either you have to write s.foo, or S.foo. And if the address of a static belongs to a type, shouldn't this resolve the ambiguities?
Feb 12 2018
On Monday, 12 February 2018 at 09:37:56 UTC, Simen Kjærås wrote:Not really, since D doesn't have a concept of an address associated with a type, only with instances of it. So when you use a static array, the address is hard-coded. -- SimenOk... so the query on ptr on a static is not to be allowed? And the fact I can perform it is a bug?
Feb 12 2018
On Monday, 12 February 2018 at 09:58:13 UTC, Alex wrote:On Monday, 12 February 2018 at 09:37:56 UTC, Simen Kjærås wrote:I'm sorry, I was apparently unclear. When I said 'static array' above, I meant 'static member'. Since we've been using arrays in our examples, there could be conflation of ideas there. The fact that you can access (and even modify) the static member's .ptr property (as in S.arr.ptr = [1,2,3].ptr), doesn't mean you can change the address of the array itself (the static data in S). This can be shown by writeln(&S.arr), which will not change. When you call a static method, as the one in this example: struct S { static int[] arr; static void foo() { arr[0]++; } } unittest { S.foo(); } No pointer is being passed to foo - it's exactly equivalent to this code: module test; int[] arr; void foo() { arr[0]++; } unittest { foo(); } Likewise, when a non-static method modifies a static member, it doesn't need to look up the address of the static member - its address is hard-coded. As an example, try this: struct S { static int n1; int n2; } unittest { import std.stdio; S s1; S s2; // These should be equal: writeln(&s1.n1); writeln(&s2.n1); // These should be different: writeln(&s1.n2); writeln(&s2.n2); } -- SimenNot really, since D doesn't have a concept of an address associated with a type, only with instances of it. So when you use a static array, the address is hard-coded. -- SimenOk... so the query on ptr on a static is not to be allowed? And the fact I can perform it is a bug?
Feb 12 2018
On Monday, 12 February 2018 at 11:25:40 UTC, Simen Kjærås wrote:I'm sorry, I was apparently unclear. When I said 'static array' above, I meant 'static member'. Since we've been using arrays in our examples, there could be conflation of ideas there. The fact that you can access (and even modify) the static member's .ptr property (as in S.arr.ptr = [1,2,3].ptr), doesn't mean you can change the address of the array itself (the static data in S). This can be shown by writeln(&S.arr), which will not change. When you call a static method, as the one in this example: struct S { static int[] arr; static void foo() { arr[0]++; } } unittest { S.foo(); } No pointer is being passed to foo - it's exactly equivalent to this code: module test; int[] arr;/* yeah... just saw it in the AST-output. However, even if this is rewrited, I cannot reference to the arr as .arr I have to write S.arr */void foo() { arr[0]++; } unittest { foo(); } Likewise, when a non-static method modifies a static member, it doesn't need to look up the address of the static member - its address is hard-coded. As an example, try this: struct S { static int n1; int n2; } unittest { import std.stdio; S s1; S s2; // These should be equal: writeln(&s1.n1); writeln(&s2.n1);// sure, this is because the type of s1 and s2 is the same.// These should be different: writeln(&s1.n2); writeln(&s2.n2); } -- SimenIt is even worse, then I thought. Let us simplify our examples a little bit: /// --- code --- /// import std.typecons; struct S { static int i; } alias T = Typedef!S; struct U { static int i; } static assert(is(typeof(S.i) == int)); static assert(is(typeof(T.i) == void)); void main() { S.i = 42; assert(U.i != S.i); } /// --- code ends --- /// So... I'm starting to see your point now, I think. What I expected from the Typedef was an ability to "templatify" a type ad-hoc. I wanted to say, well, I have a dedicated type and some different manifestations of it which I define by a Typedef. After that, I could write some functions for different Typedefs being sure, that only the right types would be addressed by the functions, as specified in the example of Typedef. However, as I can see, the definition of "static" takes advantage and heaves the according member away. Not only away from instances, but also from types (which is yeah... well... lets call it unexpected :) ) However, if I define another type manually, this is not the case. So, static behaves differently on Typedefs, then on different types, defined manually.
Feb 12 2018