Transience of .front in input vs. forward ranges

Jonathan M Davis jmdavisProg at gmx.com
Mon Nov 5 17:03:45 PST 2012


On Monday, November 05, 2012 16:49:42 H. S. Teoh wrote:
> On Mon, Nov 05, 2012 at 11:51:35PM +0200, Andrei Alexandrescu wrote:
> [...]
> 
> > >With Andrei's proposal, all code that assumes transient .front with
> > >input ranges are broken by definition.
> > 
> > I think this should be: all code that DOES NOT assume transient
> > .front with input ranges is broken.
> 
> Then std.array.array is broken by definition, and cannot be implemented
> with anything less than a forward range. This will very likely break a
> lot of existing code.

We can create an hasTransientFront trait for checking whether front is 
transient or not. It can't be 100% accurate, but it would fall on the side of 
declaring something transient when it wasn't, so it wouldn't declare something 
transient to be non-transient. Then any range for which hasTransientFront was 
false could work with std.array.array. For the rest, they can do something 
like

auto arr = std.array.array(map!"a.dup"(file.byLine()));

But it's certainly true that fixing std.array.array will break code, which is 
annoying. But as long as front can be transient, there's no way around that. 
byLine cannot possibly work with std.array.array as it stands. The only 
solutions that I see at this point are

1. Exclude transience completely.

2. Mark ranges as transient in some way and force algorithms to take this new 
trait into account.

3. Insist that input ranges have transient fronts (save perhaps when it can be 
statically verified that they aren't based on front's type) and that anything 
requiring a non-transient front require forward ranges.

4. Make all ranges non-transient but provide a way to get at a transient 
version of it and force algorithms to take this new property into account.

All 4 solutions have problems. They just have different problems.

> I still think forcing input ranges to be transient is oversimplifying
> the issue. Whether a range is transient is orthogonal to whether you can
> .save the current position or whether you can traverse it in two
> directions. Trying to conflate the two only leads to leaky abstractions.

I completly agree that transience and whether something is an input range are 
orthogonal, but we need to simplify.

> The only real solution IMO is to address the issue head-on: either
> recognize transience as an inherent property of ranges, or (re)define
> ranges to exclude all transience.

Personally, I'm all for excluding transience completely and insisting that 
anything which would be transient use opApply, but Andrei doesn't like that 
idea. It would certainly be the simplest solution though, and it probably 
wouldn't really cause much of a problem for ranges like ByLine, because in 
most cases what you do is use them with a foreach loop. std.array.array would 
be the main loss there, but if opApply is used for foreach rather than the 
range functions (I don't know which currently gets precedence), then ByLine 
can become a normal range when used with range functions (i.e. no transience) 
and just reuse its buffer with opApply. Then it would work with range-based 
functions but still avoid extra allocations when simply iterating over it. 
That would be my ideal solution at this point, but clearly not everyone 
agrees.

- Jonathan M Davis


More information about the Digitalmars-d mailing list