www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why are static arrays not ranges?

reply Jack Stouffer <jack jackstouffer.com> writes:
import std.range;

void main() {
     int[6] a = [1, 2, 3, 4, 5, 6];

     pragma(msg, isInputRange!(typeof(a)));
     pragma(msg, isForwardRange!(typeof(a)));
     pragma(msg, isRandomAccessRange!(typeof(a)));
}

$ dmd -run test.d
false
false
false

That's ridiculous. Do I have to wrap my static arrays in structs 
to get range primitives?

Is there an actual reason for this?
Sep 21 2015
next sibling parent anonymous <anonymous example.com> writes:
On Monday 21 September 2015 22:33, Jack Stouffer wrote:

 import std.range;
 
 void main() {
      int[6] a = [1, 2, 3, 4, 5, 6];
 
      pragma(msg, isInputRange!(typeof(a)));
      pragma(msg, isForwardRange!(typeof(a)));
      pragma(msg, isRandomAccessRange!(typeof(a)));
 }
 
 $ dmd -run test.d
 false
 false
 false
 
 That's ridiculous. Do I have to wrap my static arrays in structs 
 to get range primitives?
You can just slice them: `a[]` is an `int[]` which is a range.
 Is there an actual reason for this?
How would popFront work on an `int[6]`? popFront can't change the type, but it must remove an element.
Sep 21 2015
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 21 September 2015 at 20:33:10 UTC, Jack Stouffer wrote:
     pragma(msg, isInputRange!(typeof(a)));
try: pragma(msg, isInputRange!(typeof(a[]))); Notice the addition of the [] after the a. That's the slicing operator and it will yield a range.
 Is there an actual reason for this?
A static array is a container; a block of memory. A range is a *view* into a container. When you popFront a range, you aren't modifying the underlying memory, you are just advancing the view to the next element. popFront of a static array is impossible anyway due to the immutability of its length, but even if it was possible, advancing your view to the next item should not actually delete the item if at all possible. Dynamic arrays are actually similar btw, the underlying container for them is just hidden from view because the garbage collector manages it, so all you see is the slice (view/range).
Sep 21 2015
prev sibling next sibling parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
On Monday, 21 September 2015 at 20:33:10 UTC, Jack Stouffer wrote:
 import std.range;

 void main() {
     int[6] a = [1, 2, 3, 4, 5, 6];

     pragma(msg, isInputRange!(typeof(a)));
     pragma(msg, isForwardRange!(typeof(a)));
     pragma(msg, isRandomAccessRange!(typeof(a)));
 }

 $ dmd -run test.d
 false
 false
 false

 That's ridiculous. Do I have to wrap my static arrays in 
 structs to get range primitives?

 Is there an actual reason for this?
A static array has a constant length, so it is not possible to popFront on a static array. Making a dynamic array from it is easy, just slice it with []: pragma(msg, isInputRange!(typeof(a[]))); pragma(msg, isForwardRange!(typeof(a[]))); pragma(msg, isRandomAccessRange!(typeof(a[])));
Sep 21 2015
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 21 September 2015 at 20:39:55 UTC, Jesse Phillips 
wrote:
 A static array has a constant length, so it is not possible to 
 popFront on a static array.

 Making a dynamic array from it is easy, just slice it with []:

      pragma(msg, isInputRange!(typeof(a[])));
      pragma(msg, isForwardRange!(typeof(a[])));
      pragma(msg, isRandomAccessRange!(typeof(a[])));
Thanks for all of the replies. I was under the impression that the slicer allocated GC, but some tests show that's not true.
Sep 21 2015
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, September 21, 2015 20:46:51 Jack Stouffer via Digitalmars-d-learn
wrote:
 On Monday, 21 September 2015 at 20:39:55 UTC, Jesse Phillips
 wrote:
 A static array has a constant length, so it is not possible to
 popFront on a static array.

 Making a dynamic array from it is easy, just slice it with []:

      pragma(msg, isInputRange!(typeof(a[])));
      pragma(msg, isForwardRange!(typeof(a[])));
      pragma(msg, isRandomAccessRange!(typeof(a[])));
Thanks for all of the replies. I was under the impression that the slicer allocated GC, but some tests show that's not true.
All that slicing a static array does is give you a dynamic array which refers to the static array. It's then the same as any other dynamic array except that you have to make sure that it doesn't continue to refer to the static array after the static array no longer exists, and it's guaranteed to have no extra capacity, so if you do append to it, it's guaranteed to reallocate, whereas one allocated via new may or may not have extra capacity, depending on what's been done with that dynamic array and any other dynamic arrays were sliced from it and thus may or may not have to be reallocated when it's appended to. Similarly, slicing malloced memory gets you a dynamic array which refers to malloced memory and thus has no extra capacity, and you have to be careful to not still have it around when the malloced memory is freed. I would suggest that you read this http://dlang.org/d-array-article.html and possibly watch this http://dconf.org/2015/talks/davis.html - Jonathan M Davis
Sep 21 2015
prev sibling next sibling parent cym13 <cpicard openmailbox.org> writes:
On Monday, 21 September 2015 at 20:33:10 UTC, Jack Stouffer wrote:
 import std.range;

 void main() {
     int[6] a = [1, 2, 3, 4, 5, 6];

     pragma(msg, isInputRange!(typeof(a)));
     pragma(msg, isForwardRange!(typeof(a)));
     pragma(msg, isRandomAccessRange!(typeof(a)));
 }

 $ dmd -run test.d
 false
 false
 false

 That's ridiculous. Do I have to wrap my static arrays in 
 structs to get range primitives?

 Is there an actual reason for this?
For an element of explanation see my answer at a similar question here: http://forum.dlang.org/post/xdhuberedpjuxydbwdip forum.dlang.org
Sep 21 2015
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Monday, 21 September 2015 at 20:33:10 UTC, Jack Stouffer wrote:
 That's ridiculous. Do I have to wrap my static arrays in 
 structs to get range primitives?

 Is there an actual reason for this?
I had done basically the same thing. Below is my naive implementation. import std.traits; import std.range; import std.array : array; import std.stdio : writeln; import std.algorithm : map; struct hybrid_array(T : U[N], U, size_t N) if ( isStaticArray!T ) { T static_array; private auto _length = static_array.length; auto domain = iota(0, static_array.length); this(T x) { static_array = x; } property bool empty() { return domain.empty; } property size_t length() { return _length; } property U front() { assert(!empty); return static_array[domain.front]; } void popFront() { assert(!empty); domain.popFront; _length--; } property hybrid_array save() { return this; } property U back() { assert(!empty); return static_array[domain.back]; } void popBack() { assert(!empty); domain.popBack; _length++; } U opIndex(size_t val) { assert(!empty); return static_array[domain[val]]; } } void main() { int[5] x = [0, 10, 2, 6, 1]; //auto squares = map!(a => a * a)(x); //doesn't work auto range = iota(0, x.length).array; alias h_array = hybrid_array!(int[5]); auto y = h_array(x); writeln( isRandomAccessRange!(typeof(y)) ); auto squares = map!(a => a * a)(y); //success, does work writeln(squares); }
Sep 21 2015