How to correctly handle immutable ranges

monarch_dodra monarchdodra at gmail.com
Mon Dec 31 08:29:25 PST 2012


On Monday, 31 December 2012 at 14:58:03 UTC, Peter Alexander 
wrote:
> On Monday, 31 December 2012 at 14:24:53 UTC, monarch_dodra 
> wrote:
>> The same can't be said about ranges: a "immutable(Range!T)" 
>> might not safely copyable as a "Range!(immutable(T))"
>
> Hmm, are you sure? Can you give an example?

Yes, any (well, most) reference type range will fail the 
conversion. For example:

import std.array;

//---
struct ShallowRange(T)
{
   T[]* payload;

   T front() const {return (*payload).front;}
   void popFront(){(*payload).popFront;}
   bool empty() const {return (*payload).empty;}
}

ShallowRange!T shallowRange(T)(ref T[] data)
{
   return ShallowRange!T(&data);
}

immutable(ShallowRange!T) immutableShallowRange(T)(ref 
immutable(T[]) data)
{
   return cast(immutable(ShallowRange!T)) 
ShallowRange!T(cast(T[]*)&data);
}

void main()
{
   immutable(int)[] slice  = [1, 2, 3];
   immutable(int[]) iSlice = [1, 2, 3];

   ShallowRange!(immutable(int)) range  = shallowRange(slice);
   immutable(ShallowRange!int)   iRange = 
immutableShallowRange(iSlice);
}
//---

Here, I have a slice of immutables (slice) and an immutable slice 
(iSlice), which I place in a range of immutables, and an 
immutable range (respectivelly).

If you cast my immutable range to a range of immutables, and then 
attempt to iterate over it, you are going to modify my immutable 
iSlice...

>  Surely if Range is  a struct...

I'm not well versed in how classes and immutability work 
(especially when discussing the immutability of the class object 
itself, vs the class + class reference).

But yeah, keep in mind a range can be implemented as a class.

> ... and everything is copied then it can all change from 
> mutable to immutable (using a postblit where necessary).
>
> Maybe we just need copy constructors for this to work around 
> the const issue with postblit.

I think this is a language wide issue (well, concept). A range 
really is no different from any other object, and you really 
can't know what will happen when you copy them.

As a general rule, even via CC, you can't assume the result of 
copying a "immutable(S!T)" (or "immutable(S!(immutable(T))") will 
be a "S!(immutable(T)".

--------
But back to the original problem, I just think one shouldn't be 
able to call a const object a range. A "Range" is mutable by 
nature. Any attempt to pass one to an algorithm should fail (IMO).

I've yet to see anybody try to manipulate const ranges anyways 
(which probably isn't a coincidence), though someone one prove me 
wrong/disagree.

We just have a really special case regarding const slices. Even 
then, the only reason you can "iterate them" is because the 
compiler is implicitly copying a mutable slice behind the scenes. 
The const slice itself, technically, really isn't iterable 
(AFAIK)...

I think the slices' behavior twists our view of what to expect 
from the rest of our ranges.


More information about the Digitalmars-d mailing list