www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.array.array seems to return flatten copy of input

reply "Olivier Grant" <against.the evil.bots.com> writes:
Hi,

I've started using D as a scripting language at work and for 
personal projects as a means to learn the language and I've 
bumped into a case where I would like to iterate a slice by a 
certain number of elements at a time such that :

foreach(s; [1,2,3,4].splice!(2))
{
    writeln(s);
}

would print :

[1,2]
[3,4]

First of all, is there such a function in D's standard library as 
I didn't seem to be able to find one ?

I ended up implementing the following :

import std.stdio;
import std.range;
import std.array;

auto splice( size_t N, R )( R range )
    if(isInputRange!R)
{
    struct Splicer
    {
       R array;

        property bool empty( ) const
       { return 0 == array.length; }

        property auto front( ) const
       { return array[0 .. N]; }

       void popFront( )
       { array = array[N .. $]; }
    }

    static assert(isInputRange!Splicer);

    assert(range.length % N == 0);

    Splicer res = { range };
    return res;
}

unittest
{
    assert(equal([1,2,3,4].splice!(2), [[1,2],[3,4]]));
}

void main( )
{
    auto a = [1,2,3,4];

    writeln(a.splice!(2));
    writeln(a.splice!(2).array);
}

which weirdly enough gives me the following output :

[[1,2],[3,4]] // I expect that.
[1,2,3,4] // But what is happening here ?

I'm obviously doing something wrong but I can't figure out what.

Thanks for the help in advance,

O.
Apr 04 2014
next sibling parent "anonymous" <anonymous example.com> writes:
On Friday, 4 April 2014 at 20:19:53 UTC, Olivier Grant wrote:

 iterate a slice by a certain number of elements at a time such 
 that :

 foreach(s; [1,2,3,4].splice!(2))
 {
    writeln(s);
 }

 would print :

 [1,2]
 [3,4]

 First of all, is there such a function in D's standard library 
 as I didn't seem to be able to find one ?
std.range.chunks
Apr 04 2014
prev sibling next sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
On Friday, 4 April 2014 at 20:19:53 UTC, Olivier Grant wrote:
 Hi,

 I've started using D as a scripting language at work and for 
 personal projects as a means to learn the language and I've 
 bumped into a case where I would like to iterate a slice by a 
 certain number of elements at a time such that :

 foreach(s; [1,2,3,4].splice!(2))
 {
    writeln(s);
 }

 would print :

 [1,2]
 [3,4]

 First of all, is there such a function in D's standard library 
 as I didn't seem to be able to find one ?
http://dlang.org/phobos/std_range.html#chunks
Apr 04 2014
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Friday, 4 April 2014 at 20:19:53 UTC, Olivier Grant wrote:
 import std.stdio;
 import std.range;
 import std.array;

 auto splice( size_t N, R )( R range )
    if(isInputRange!R)
 {
    struct Splicer
    {
       R array;

        property bool empty( ) const
       { return 0 == array.length; }

        property auto front( ) const
       { return array[0 .. N]; }

       void popFront( )
       { array = array[N .. $]; }
    }

    static assert(isInputRange!Splicer);

    assert(range.length % N == 0);

    Splicer res = { range };
    return res;
 }

 unittest
 {
    assert(equal([1,2,3,4].splice!(2), [[1,2],[3,4]]));
 }

 void main( )
 {
    auto a = [1,2,3,4];

    writeln(a.splice!(2));
    writeln(a.splice!(2).array);
 }

 which weirdly enough gives me the following output :

 [[1,2],[3,4]] // I expect that.
 [1,2,3,4] // But what is happening here ?
a.splice!(2).array is the field of the Splicer struct. Rename that or call std.array.array not via UFCS.
Apr 04 2014
parent reply "Olivier Grant" <against.the evil.bots.com> writes:
That is one responsive D community :) Thank you to all three of 
you for these quick answers.

I was really scratching my head on that one. This shows that UFCS 
can be quite dangerous. Is there any way to hide Splicer.array to 
the outside world? It just seems that it would be very easy to 
break client code by updating your implementation if you end up 
using a name that is already used elsewhere and accessed using 
UFCS.


Thanks,

O.

On Friday, 4 April 2014 at 20:29:28 UTC, anonymous wrote:
 On Friday, 4 April 2014 at 20:19:53 UTC, Olivier Grant wrote:
 import std.stdio;
 import std.range;
 import std.array;

 auto splice( size_t N, R )( R range )
   if(isInputRange!R)
 {
   struct Splicer
   {
      R array;

       property bool empty( ) const
      { return 0 == array.length; }

       property auto front( ) const
      { return array[0 .. N]; }

      void popFront( )
      { array = array[N .. $]; }
   }

   static assert(isInputRange!Splicer);

   assert(range.length % N == 0);

   Splicer res = { range };
   return res;
 }

 unittest
 {
   assert(equal([1,2,3,4].splice!(2), [[1,2],[3,4]]));
 }

 void main( )
 {
   auto a = [1,2,3,4];

   writeln(a.splice!(2));
   writeln(a.splice!(2).array);
 }

 which weirdly enough gives me the following output :

 [[1,2],[3,4]] // I expect that.
 [1,2,3,4] // But what is happening here ?
a.splice!(2).array is the field of the Splicer struct. Rename that or call std.array.array not via UFCS.
Apr 04 2014
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 04 Apr 2014 16:35:57 -0400, Olivier Grant  
<against.the evil.bots.com> wrote:

 That is one responsive D community :) Thank you to all three of you for  
 these quick answers.

 I was really scratching my head on that one. This shows that UFCS can be  
 quite dangerous. Is there any way to hide Splicer.array to the outside  
 world? It just seems that it would be very easy to break client code by  
 updating your implementation if you end up using a name that is already  
 used elsewhere and accessed using UFCS.
I advise to call it _array to prevent such issues. Note, you can make the field private, but that is a module-level directive. In order for it to apply, main would have to be in a separate module. In that case, the code would simply fail to compile. As a rule, members ALWAYS have precedence over UFCS functions. -Steve
Apr 04 2014
parent "Olivier Grant" <against.the evil.bots.com> writes:
Sorry Steven,

I hadn't seen your answer.

Thanks for the extra information.

O.

On Friday, 4 April 2014 at 20:42:32 UTC, Steven Schveighoffer 
wrote:
 On Fri, 04 Apr 2014 16:35:57 -0400, Olivier Grant 
 <against.the evil.bots.com> wrote:

 That is one responsive D community :) Thank you to all three 
 of you for these quick answers.

 I was really scratching my head on that one. This shows that 
 UFCS can be quite dangerous. Is there any way to hide 
 Splicer.array to the outside world? It just seems that it 
 would be very easy to break client code by updating your 
 implementation if you end up using a name that is already used 
 elsewhere and accessed using UFCS.
I advise to call it _array to prevent such issues. Note, you can make the field private, but that is a module-level directive. In order for it to apply, main would have to be in a separate module. In that case, the code would simply fail to compile. As a rule, members ALWAYS have precedence over UFCS functions. -Steve
Apr 04 2014
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Olivier Grant:

 Is there any way to hide Splicer.array to the outside world?
If your splice is inside another module, and you tag the array field with private, you will receive an error: auto splice( size_t N, R )( R range ) if(isInputRange!R) { struct Splicer { private R array; This avoids your mistake, but also forbids you to use the std.array.array on a splice with UFCS. Is this acceptable for you? Bye, bearophile
Apr 04 2014
parent "Olivier Grant" <against.the evil.bots.com> writes:
Yes, that definitely seems like a good start. To be honest, I not 
familiar enough yet with how you are suppose to organise your 
source code in D.

Is there any agreed-on naming convention when it comes to member 
variables to avoid that kind of name clash ?

Thanks,

O.

On Friday, 4 April 2014 at 20:44:36 UTC, bearophile wrote:
 Olivier Grant:

 Is there any way to hide Splicer.array to the outside world?
If your splice is inside another module, and you tag the array field with private, you will receive an error: auto splice( size_t N, R )( R range ) if(isInputRange!R) { struct Splicer { private R array; This avoids your mistake, but also forbids you to use the std.array.array on a splice with UFCS. Is this acceptable for you? Bye, bearophile
Apr 04 2014