Working with ranges

Elmar chrehme at gmx.de
Sat May 29 19:55:30 UTC 2021


On Wednesday, 26 May 2021 at 15:07:12 UTC, Jack wrote:
> On Wednesday, 26 May 2021 at 13:58:56 UTC, Elmar wrote:
>> On Saturday, 8 December 2018 at 03:51:02 UTC, Adam D. Ruppe 
>> wrote:
>>> [...]
>>
>> That's amazing, this should be one thing that should appear in 
>> every tutorial just right at the start! I was looking hours 
>> for a way to generate an "iterator" (a range) from a 
>> fixed-size array which doesn't copy the elements (unless 
>> elements are deleted/added).
>>
>> [...]
>
> maybe array from std.array to make that range in array of its 
> own?

The main incentive here is, that I would like to obtain an 
iterator (some kind of access view) over a background storage 
which can be anywhere in memory which I don't care about. It 
might be on stack frame. In many or most of the cases the use 
case doesn't actually require GC-allocation. `array()` does 
GC-allocation and personally, I think `array()` should be avoided 
whereever the use case doesn't justify GC-allocation, at least if 
you care for *logically correct* memory management of your 
program.
GC-allocation might just work the same way (most of the time even 
better than with stack-allocated storage due to design of D) and 
it adds convenience for you to omit explicit destruction calls 
which can spare you some conditional checks if the need for 
destruction depends on runtime cases. But with logical 
correctness I mean appropriateness here, an allocation scheme 
which reflects the nature of a variable's lifetime correctly. For 
example, if the lifetime, maximum storage requirements or the 
de-/allocation points in code are already known at compile-time 
then GC-allocation isn't appropriate. It has many drawbacks in 
performance critical sections, such as non-deterministic 
destruction time (which probably is the worst), the overhead of 
scanning GC-allocated regions and the memory fragmentation caused 
by dynamic allocation (i.e. non-deterministic available storage 
space) and in the worst case provides additional attack vectors, 
e.g. with heap overflows or use-after-free. In many cases, it is 
just better to GC-allocate an entire growable pool or slaps of 
objects for fast use-case specific allocation.


So whatfor I would like to use an iterator? An iterator basically 
is a meta-data structure which stores meta data (like indices and 
pointers) for accessing another data structure's contents. And if 
I just want to change the access of or iteration over a data 
structure then I don't need to touch how the actual data or 
memory is stored and I don't even require expensive memory 
allocation when I could rearrange the iterator contents inplace 
and if the meta data is much smaller than the actual data. All 
that is not achieved by `array()`. `array()` is not an iterator 
but a dynamically allocated copy. Using an iterator like 
`array[]` saves me expensive GC-allocations. When I only want to 
access a data structure but not mofify it then GC-allocation 
would not fit the lifetime logic of a variable.

When I understand correctly then the iterator concept in D is 
called "range". Ranges neither designate a data structure nor a 
specific data arrangement but it defines a generic access 
interface of aggregate data whose purpose is to work independent 
of whatever data structure is accessed via this interface.

Now, I'm only missing methods to allocate range iterators on the 
stack or modifying iterators inplace.


More information about the Digitalmars-d-learn mailing list