Alias this with array can only be used once

Jonathan M Davis jmdavisProg at gmx.com
Wed Feb 22 14:40:17 PST 2012


On Wednesday, February 22, 2012 23:28:47 Simen Kjærås wrote:
> On Wed, 22 Feb 2012 23:16:41 +0100, Blake Anderton <rbanderton at 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


More information about the Digitalmars-d-learn mailing list