digitalmars.D.learn - foreach on a tuple using aliases
- Steven Schveighoffer (31/31) Aug 05 2018 I have found something that looks like a bug to me, but also looks like
- Alex (18/51) Aug 05 2018 Another workaround would be
- Steven Schveighoffer (7/19) Aug 06 2018 I did try static foreach, but it doesn't work.
- Timon Gehr (4/46) Aug 05 2018 It's a bug. The two copies of 'item' are not supposed to be the same
- Steven Schveighoffer (9/19) Aug 06 2018 Yep. I even found it has nothing to do with foreach on a tuple:
- Timon Gehr (2/14) Aug 06 2018 It shouldn't.
I have found something that looks like a bug to me, but also looks like it could simply be a limitation of the foreach construct. Consider this code: struct Foo {} enum isFoo(alias x) = is(typeof(x) == Foo); void main() { Foo foo; assert(isFoo!foo); static struct X { int i; Foo foo; } X x; foreach(i, ref item; x.tupleof) static if(is(typeof(item) == Foo)) // line A static assert(isFoo!item); // line B else static assert(!isFoo!item); } Consider just the two lines A and B. If you saw those lines anywhere, given the isFoo definition, you would expect the assert to pass. But in this case, it fails. What is happening is that the first time through the loop, we are considering x.i. This is an int, and not a Foo, so it assigns false to the template isFoo!item. The second time through the loop on x.foo, the compiler decides that it ALREADY FIGURED OUT isFoo!item, and so it just substitutes false, even though the item in question is a different item. So is this a bug? Is it expected? Is it too difficult to fix? The workaround of course is to use x.tupleof[i] when instantiating isFoo. But it's a bit ugly. I can also see other issues cropping up if you use `item` for other meta things. -Steve
Aug 05 2018
On Sunday, 5 August 2018 at 14:07:30 UTC, Steven Schveighoffer wrote:I have found something that looks like a bug to me, but also looks like it could simply be a limitation of the foreach construct. Consider this code: struct Foo {} enum isFoo(alias x) = is(typeof(x) == Foo); void main() { Foo foo; assert(isFoo!foo); static struct X { int i; Foo foo; } X x; foreach(i, ref item; x.tupleof) static if(is(typeof(item) == Foo)) // line A static assert(isFoo!item); // line B else static assert(!isFoo!item); } Consider just the two lines A and B. If you saw those lines anywhere, given the isFoo definition, you would expect the assert to pass. But in this case, it fails. What is happening is that the first time through the loop, we are considering x.i. This is an int, and not a Foo, so it assigns false to the template isFoo!item. The second time through the loop on x.foo, the compiler decides that it ALREADY FIGURED OUT isFoo!item, and so it just substitutes false, even though the item in question is a different item. So is this a bug? Is it expected? Is it too difficult to fix? The workaround of course is to use x.tupleof[i] when instantiating isFoo. But it's a bit ugly. I can also see other issues cropping up if you use `item` for other meta things. -SteveAnother workaround would be ´´´ void main() { Foo foo; assert(isFoo!foo); static struct X { int i; Foo foo; } X x; static foreach(i, item; typeof(x).tupleof) static if(is(typeof(item) == Foo)) // line A static assert(isFoo!item); // line B else static assert(!isFoo!item); } ´´´ wouldn't it?
Aug 05 2018
On 8/5/18 10:48 AM, Alex wrote:void main() { Foo foo; assert(isFoo!foo); static struct X { int i; Foo foo; } X x; static foreach(i, item; typeof(x).tupleof) static if(is(typeof(item) == Foo)) // line A static assert(isFoo!item); // line B else static assert(!isFoo!item); }I did try static foreach, but it doesn't work. The difference here is you are using typeof(x).tupleof, whereas I want x.tupleof. Note that in my real code, I do more than just the static assert, I want to use item as a reference to the real field in x. -Steve
Aug 06 2018
On 05.08.2018 16:07, Steven Schveighoffer wrote:I have found something that looks like a bug to me, but also looks like it could simply be a limitation of the foreach construct. Consider this code: struct Foo {} enum isFoo(alias x) = is(typeof(x) == Foo); void main() { Foo foo; assert(isFoo!foo); static struct X { int i; Foo foo; } X x; foreach(i, ref item; x.tupleof) static if(is(typeof(item) == Foo)) // line A static assert(isFoo!item); // line B else static assert(!isFoo!item); } Consider just the two lines A and B. If you saw those lines anywhere, given the isFoo definition, you would expect the assert to pass. But in this case, it fails. What is happening is that the first time through the loop, we are considering x.i. This is an int, and not a Foo, so it assigns false to the template isFoo!item. The second time through the loop on x.foo, the compiler decides that it ALREADY FIGURED OUT isFoo!item, and so it just substitutes false, even though the item in question is a different item. So is this a bug? Is it expected?It's a bug. The two copies of 'item' are not supposed to be the same symbol. (Different types -> different symbols.)Is it too difficult to fix? ...Unlikely.The workaround of course is to use x.tupleof[i] when instantiating isFoo. But it's a bit ugly. I can also see other issues cropping up if you use `item` for other meta things. -Steve
Aug 05 2018
On 8/5/18 11:40 AM, Timon Gehr wrote:On 05.08.2018 16:07, Steven Schveighoffer wrote:Yep. I even found it has nothing to do with foreach on a tuple: https://run.dlang.io/is/vxQlIi I wonder though, it shouldn't really be a different type that triggers it, right? I mean 2 separate aliases to different variables that are the same type, I would hope would re-instantiate. Otherwise something like .offsetof would be wrong.So is this a bug? Is it expected?It's a bug. The two copies of 'item' are not supposed to be the same symbol. (Different types -> different symbols.)https://issues.dlang.org/show_bug.cgi?id=19145 -SteveIs it too difficult to fix? ...Unlikely.
Aug 06 2018
On 06.08.2018 14:37, Steven Schveighoffer wrote:On 8/5/18 11:40 AM, Timon Gehr wrote:It shouldn't.On 05.08.2018 16:07, Steven Schveighoffer wrote:Yep. I even found it has nothing to do with foreach on a tuple: https://run.dlang.io/is/vxQlIi I wonder though, it shouldn't really be a different type that triggers it, right?So is this a bug? Is it expected?It's a bug. The two copies of 'item' are not supposed to be the same symbol. (Different types -> different symbols.)
Aug 06 2018