User defined type and foreach

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Nov 17 01:16:38 UTC 2017


On Fri, Nov 17, 2017 at 01:06:31AM +0000, Tony via Digitalmars-d-learn wrote:
[...]
> But I do have a complaint about the methods empty(), popFront() and
> pop(). I think they should have a special syntax or name to reflect
> that they are not general purpose methods. __empty() or preferably
> __forEachDone().  empty() is typically used to say if a container has
> no data,  not if you are at the end of external foreach loop
> processing. pop() and popFront() also would typically have different
> meanings with certain containers and their names don't reflect that
> they have a special "external foreach loop" purpose.

It should be .empty, .popFront, and .front, not .pop.

Also, these methods are *range* primitives, and over time, we have come
to a consensus that generally speaking, it's a bad idea to conflate
containers with ranges over containers.  The main thing is that
iterating over a range is supposed to consume it, which is usually not
what you want with a container.

The usual idiom is to separate the two concepts, and have the container
provide a mechanism for returning a range over its contents, usually via
.opIndex with no arguments, or .opSlice. Then you would just write:

	foreach (e; myContainer[]) { // [] calls .opIndex/.opSlice
		...
	}

Unfortunately, built-in arrays, which are also ranges, are one exception
to this rule that, due to their ubiquity in D, also serve to mislead
newcomers to D about when/where range primitives should be implemented.
Generally speaking, built-in arrays should not be considered exemplary
in this respect, but rather should be understood as exceptions.  The
general convention is to separate your containers from ranges over its
contents, and to provide .opIndex / .opSlice that constructs a range
over the container when needed.

The other consideration is that if you don't really need range
functionality, i.e., the only thing you want to do with your container
is to put it in a foreach loop, then you can sidestep this whole mess
and just implement .opApply for your container and call it a day.  Of
course, then you won't be able to use generic algorithms like those in
std.algorithm with your container, but if you didn't intend to anyway,
it's not a big deal.


T

-- 
Heads I win, tails you lose.


More information about the Digitalmars-d-learn mailing list