Transience of .front in input vs. forward ranges

deadalnix deadalnix at gmail.com
Tue Oct 30 16:00:50 PDT 2012


Le 30/10/2012 23:29, H. S. Teoh a écrit :
> Now that Andrei is back (I think?), I want to bring up this discussion
> again, because I think it's important.
>

Interesting post.

It appears to me that invalidating .front is done for performances 
reasons most of the time. As this is the unsafe face of the coin, I 
strongly think that this shouldn't be the default behavior.

To me the best solution is to provide a function or a property on ranges 
that provide the unsafe version of the range.

It is easy to provide a default implementation as UFCS that is a NOOP so 
no code is being broken.

With that design, it is possible to provide an always safe interface 
while allowing algorithm that can handle non persistent .front to run at 
full speed.

As it is always safe to provide a range that persist .front when a range 
that do not persist it is expected, no code needs to be broken. 
Obviously, the performance boost will not show up in this case :D

byLine and alike will have to be modified to follow this policy, but 
hopefully, no code should be broken in the process.

If I use your permuting example, it should be done as follow :

struct InvalidatingAllPermutations(T) {
	T[] current, first;
	bool done;

	this(T[] initialBuf) {
		first = initialBuf;
		current = first.dup;
	}

	void popFront() {
		nextPermutation(current);
		if (equal(current, first))
			done = true;
	}

	@property bool empty() {
		return !done;
	}

	@property T[] front() {
		return current;
	}

	auto save() {
		AllPermutations!T copy;
		copy.front = this.front;
		copy.first = this.first;
		copy.done = this.done;
		return copy;
	}
}

struct AllPermutations(T) {
	InvalidatingAllPermutations!T innerRange;
	alias innerRange this;

	T[] current;

	this(T[] initialBuf) {
		innerRange = InvalidatingAllPermutations!T(initialBuf);
		current = innerRange.front.dup;
	}

	@property T[] front() {
		return current;
	}

	void popFront() {
		innerRange.popFront();
		current = innerRange.front.dup;
	}
}

I do think this is the way that conciliate safe as default but still 
allow to be fast when needed, without adding much on most code.


More information about the Digitalmars-d mailing list