Proposed Changes to the Range API for Phobos v3

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu May 16 16:22:06 UTC 2024


On Thursday, May 16, 2024 9:33:26 AM MDT Richard (Rikki) Andrew Cattermole via 
Digitalmars-d wrote:
> Two things I suggest we consider, given the write up:
>
> 1. Automatic boxing of slices into a struct, this was something I was
> considering for signatures specifically for ranges.

What would that buy us? I don't see how it adds any value.

I guess that having a struct would negate the need to import the range API
functions for arrays, but instead, we'd have to import the struct (or put it
in object.d), and then we'd have to explicitly wrap arrays, whereas right
now, all you need is an import to treat arrays as ranges, and with my
proposed changes, you wouldn't even need that anymore.

Also, considering that ranges are basically supposed to be an abstraction of
dynamic arrays / slices, similar to how C++ iterators are an abstraction of
pointers, having to wrap dynamic arrays in structs is arguably taking things
in the wrong direction. It would be making it so that dynamic arrays aren't
ranges instead of making ranges in general more like dynamic arrays.

It would also get really annoying to have to constantly wrap arrays just to
pass them to range-based code - and it would get extra awkward in the cases
where a function that used to operate on an array was changed to operate on
a range instead, since then you'd either be forced to treat arrays
differently than normal with such a function or break code that used to pass
arrays, forcing it to wrap them in a struct. And since strings are dynamic
arrays, all of this would apply to strings too.

>From what I can see, trying to stop dynamic arrays / slices as ranges just
makes things worse.

> 2. Enable passing the this pointer on a class explicitly, coupled with a
> few final methods you could handle when the class is null and then
> forward to the implementation.

That would destroy our ability to rely on the copy or assignment semantics
of ranges. The whole point of disallowing pointers or classes as ranges
would be so that we can rely on forward ranges being copied without needing
a function like save - and so that we can rely on the init value being
valid. Having free functions to handle the case where a class reference was
null would fix the init problem (at the cost of needing to import those
functions), but it doesn't solve the problem that we cannot have reliable
copy or assignment semantics if we allow reference types to be ranges.

Requiring that class references be wrapped in structs allows us to have
reliable copy and assignment semantics without losing any functionality, and
it makes the semantics of ranges in general more consistent - and closer to
that of dynamic arrays / slices. It's already the case that ranges which are
classes are pretty rare. Some use cases require them, but the vast majority
of range-based code uses structs. I really don't see any value in trying to
support naked classes as ranges when it's fairly straightforward to just
wrap them in structs and get rid of any special cases that they would
otherwise cause. And since you typically use the functions in
std.range.interfaces to generate class ranges anyway, the resulting code
would be pretty similar to what anyone using class ranges would be doing
now.

It seems like you're proposing that we start requiring wrapper structs for
some of the most common kinds of ranges, whereas my proposal would be
requiring wrapper structs only for rare ranges - ones which are already
typically generated using helper functions.

- Jonathan M Davis





More information about the Digitalmars-d mailing list