On Wednesday, February 22, 2012 23:28:47 Simen Kjærås wrote: > On Wed, 22 Feb 2012 23:16:41 +0100, Blake Anderton <rbander...@gmail.com> > > wrote: > > Why doesn't this work? I'm assuming I'm not fully understanding how > > "alias this" interacts with ranges (i.e. the range isn't being reset > > after count is finished with it), but I'm not sure how to fix this > > either: > > > > import std.algorithm; > > > > class ArrayContainer > > { > > > > int[] values; > > this(int[] v) { values = v; } > > alias values this; > > > > } > > > > void main(string[] args) > > { > > > > auto c = new ArrayContainer([1, 2, 3]); > > assert(count(c) == 3); //succeeds > > assert(c.length == 3); //FAILS - is actually zero > > > > } > > That's interesting. The thing that happens is the function popFront > is callable on ArrayContainer, and popFront mutates its parameter. > The solution is to use count(c[]), but I'm not so sure I agree with > the way this works currently.
It's the consequence of having a container which is also a range - which is what this code is doing. It's _not_ something that's a good idea. Regardless, it's not like this code could have any other behavior than it does. The template constraint on count verifies that the argument is an input range, which it is, since you can call front, popFront, and empty on it thanks to the alias this. So, the template gets instantiated with the type that you pass it - ArrayContainer. And then ArrayContainer gets consumed by count as any range would gets consumed by count. It's just that unlike most ranges, it's a class, so it doesn't get implicitly sliced or saved when you pass it in. So, instead of the slice being consumed, it itself is consumed. This is all solved by just not declaring a container which is a range. It's just asking for trouble. You don't want your container to be consumed when you pass it to range-based functions. Rather, you should be slicing it so that the _range_ gets consumed without screwing over your container. - Jonathan M Davis