Range Redesign: Copy Semantics

Quirin Schroll qs.il.paperinik at gmail.com
Tue Jan 23 16:58:21 UTC 2024


On Monday, 22 January 2024 at 05:22:44 UTC, Paul Backus wrote:
> You have N data structures and M algorithms, and by using this 
> common interface you can implement all N*M combinations in 
> O(N+M) code. Each data structure implements the range API once, 
> and each algorithm is implemented once using the range API.
>
> If you split the API in two, by making input streams (basic 
> input ranges) and forward ranges completely disjoint, you 
> undermine this goal. Now, each data structure has to implement 
> *two* APIs, and each algorithm has to be implemented *twice*, 
> once for input streams and once for forward ranges.

Not necessarily. First, any algorithm requiring a forward range 
wouldn’t be implemented twice. And, most importantly, a data 
structure would not offer input range iteration if it can offer 
forward range. Why would it?

> In practice, what's going to happen is library authors will 
> simply not bother to implement both, and we will end up with 
> gaps where many (data structure, algorithm) pairs are not 
> covered.

The only realistic concern I see with the proposal is algorithms 
being implemented requiring forward ranges when they could (also) 
work with basic input ranges. Overconstraining input is not 
specific to ranges, though.

What Jonathan never mentioned in his proposal, but something 
that, as far as I see, is true: One can wrap any forward range to 
be an input range. Heck, the pointer to any forward range is an 
input range, assuming there is a global `next(ForwardRange*)` 
function utilizing the forward range primitives. If you pass 
`&forwardRange` to an input range algorithm, it may copy it 
around as it pleases, it will change the underlying range just 
like an input range should; and you’d have the `&` for an 
indication that it does.

A problem I see with this is composition. Requiring the lifting 
to a pointer requires lvalues, and composition lives on not 
having those. The issue will generally be negligible, as most 
range algorithms returning a range will for the most part want to 
preserve as many of the abilities of the original range as 
possible. The difference in the algorithm would be that, instead 
of:
```d
// implement input range
static if (/* base range is forward range */)
     // implement forward range
static if (/* base range is bidi range */
     // implement bidi range
// etc.
```
You would have:
```d
static if (/* base range is input range */)
     // implement input range
else:
static if (/* base range is forward range */)
     // implement forward range
static if (/* base range is bidi range */)
     // implement bidi range
// etc.
```


More information about the Digitalmars-d mailing list