www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Templates: Array slices not recognized

reply "Chris" <wendlec tcd.ie> writes:
The following:

import std.stdio : writefln;
import std.range.primitives : isInputRange, hasLength;

void main() {
   size_t[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
   doSomething(a);  // works

   doSomething(a[0..5]);

// ---> Error: template slices.doSomething cannot deduce function 
from argument types !()(ulong[]), candidates are:
   // slices.d(11): slices.doSomething(R)(ref R r) if 
(isInputRange!R && hasLength!R)

   doSomething!(size_t[])(a[0..5]);
   // ---> Error: doSomething (ref ulong[] r) is not callable 
using argument types (ulong[])
}

void doSomething(R)(ref R r)
                 if (isInputRange!R && hasLength!R)  // etc..
{
   foreach (ref n; r) {
     writefln("%d * 2 = %d", n, n * 2);
   }
}

//EOF

a[0..5] is not recognized as size_t[]. If I give the compiler a 
hint with !(size_t[]), it complains again, i.e. I can not pass 
the slice as a reference.

A workaround is

size_t[] b = a[0..5];
doSomething(b);

However, this comes with a serious performance penalty in for 
loops (even if I predefine b and reuse it in the loop). 
to!(size_t[])(a[0..5]) is even worse.

Any thoughts or tips?
Apr 18 2015
parent reply Max Klyga <max.klyga gmail.com> writes:
On 2015-04-18 13:46:19 +0000, Chris said:

 The following:
 
 import std.stdio : writefln;
 import std.range.primitives : isInputRange, hasLength;
 
 void main() {
    size_t[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    doSomething(a);  // works
 
    doSomething(a[0..5]);
 
 // ---> Error: template slices.doSomething cannot deduce function from 
 argument types !()(ulong[]), candidates are:
    // slices.d(11): slices.doSomething(R)(ref R r) if (isInputRange!R 
 && hasLength!R)
 
    doSomething!(size_t[])(a[0..5]);
    // ---> Error: doSomething (ref ulong[] r) is not callable using 
 argument types (ulong[])
 }
 
 void doSomething(R)(ref R r)
                  if (isInputRange!R && hasLength!R)  // etc..
 {
    foreach (ref n; r) {
      writefln("%d * 2 = %d", n, n * 2);
    }
 }
 
 //EOF
 
 a[0..5] is not recognized as size_t[]. If I give the compiler a hint 
 with !(size_t[]), it complains again, i.e. I can not pass the slice as 
 a reference.
 
 A workaround is
 
 size_t[] b = a[0..5];
 doSomething(b);
 
 However, this comes with a serious performance penalty in for loops 
 (even if I predefine b and reuse it in the loop). 
 to!(size_t[])(a[0..5]) is even worse.
 
 Any thoughts or tips?
a[0..5] is an R-value, and cannot be passed by reference. As you noticed, once you use a variable - everything works because only L-values can be passed by reference. Also why are you passing slices by reference? Slices do not copy the memory they point to when passed by value.
Apr 18 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Saturday, 18 April 2015 at 16:26:57 UTC, Max Klyga wrote:
 On 2015-04-18 13:46:19 +0000, Chris said:

 The following:
 
 import std.stdio : writefln;
 import std.range.primitives : isInputRange, hasLength;
 
 void main() {
   size_t[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
   doSomething(a);  // works
 
   doSomething(a[0..5]);
 
 // ---> Error: template slices.doSomething cannot deduce 
 function from argument types !()(ulong[]), candidates are:
   // slices.d(11): slices.doSomething(R)(ref R r) if 
 (isInputRange!R && hasLength!R)
 
   doSomething!(size_t[])(a[0..5]);
   // ---> Error: doSomething (ref ulong[] r) is not callable 
 using argument types (ulong[])
 }
 
 void doSomething(R)(ref R r)
                 if (isInputRange!R && hasLength!R)  // etc..
 {
   foreach (ref n; r) {
     writefln("%d * 2 = %d", n, n * 2);
   }
 }
 
 //EOF
 
 a[0..5] is not recognized as size_t[]. If I give the compiler 
 a hint with !(size_t[]), it complains again, i.e. I can not 
 pass the slice as a reference.
 
 A workaround is
 
 size_t[] b = a[0..5];
 doSomething(b);
 
 However, this comes with a serious performance penalty in for 
 loops (even if I predefine b and reuse it in the loop). 
 to!(size_t[])(a[0..5]) is even worse.
 
 Any thoughts or tips?
a[0..5] is an R-value, and cannot be passed by reference. As you noticed, once you use a variable - everything works because only L-values can be passed by reference. Also why are you passing slices by reference? Slices do not copy the memory they point to when passed by value.
Doh! You're right! My bad. However, this makes the function less generic, but it doesn't matter here.
Apr 18 2015
parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Sat, 18 Apr 2015 17:50:56 +0000, Chris wrote:

 Doh! You're right! My bad. However, this makes the function less
 generic, but it doesn't matter here.
maybe `auto ref` can help here?=
Apr 18 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Saturday, 18 April 2015 at 17:59:19 UTC, ketmar wrote:
 On Sat, 18 Apr 2015 17:50:56 +0000, Chris wrote:

 Doh! You're right! My bad. However, this makes the function 
 less
 generic, but it doesn't matter here.
maybe `auto ref` can help here?
Yes, auto ref does the trick. I prefer it to passing the slice by value, because I can extend the function to cater for more types. My implementation (which is different from the one posted above) works also with strings, for example. Anyway, it gave me a performance boost of ~2.7 times as compared to the workarounds I had. This was well worth it!
Apr 20 2015
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Monday, 20 April 2015 at 09:07:54 UTC, Chris wrote:
 On Saturday, 18 April 2015 at 17:59:19 UTC, ketmar wrote:
 On Sat, 18 Apr 2015 17:50:56 +0000, Chris wrote:

 Doh! You're right! My bad. However, this makes the function 
 less
 generic, but it doesn't matter here.
maybe `auto ref` can help here?
Yes, auto ref does the trick. I prefer it to passing the slice by value, because I can extend the function to cater for more types. My implementation (which is different from the one posted above) works also with strings, for example. Anyway, it gave me a performance boost of ~2.7 times as compared to the workarounds I had. This was well worth it!
Strings are slices, too. `string` is equivalent to `immutable(char)[]`.
Apr 20 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Monday, 20 April 2015 at 09:58:06 UTC, Marc Sch├╝tz wrote:
 On Monday, 20 April 2015 at 09:07:54 UTC, Chris wrote:
 On Saturday, 18 April 2015 at 17:59:19 UTC, ketmar wrote:
 On Sat, 18 Apr 2015 17:50:56 +0000, Chris wrote:

 Doh! You're right! My bad. However, this makes the function 
 less
 generic, but it doesn't matter here.
maybe `auto ref` can help here?
Yes, auto ref does the trick. I prefer it to passing the slice by value, because I can extend the function to cater for more types. My implementation (which is different from the one posted above) works also with strings, for example. Anyway, it gave me a performance boost of ~2.7 times as compared to the workarounds I had. This was well worth it!
Strings are slices, too. `string` is equivalent to `immutable(char)[]`.
I know. My function returns an array of the same type (size_t[] or a string (immutable(char)[] or whatever). With auto ref I can pass a string without having to slice it, like so string a = "bla"; string b = "blub"; auto res = doSomething(a, b); If I didn't use "auto ref" or "ref", string would get copied, wouldn't it? auto ref doSomething(R needle, R haystack); To avoid this, I would have to write a[0..$], b[0..$], which is not nice. Right or wrong? For the record, I put the function inside a struct which again boosted the performance. No it is faster by a factor of ~3.17. Using the struct is even slightly faster than executing the same code directly within the for loop. That surprised me.
Apr 20 2015
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Mon, 20 Apr 2015 10:14:25 +0000, Chris wrote:

 string a =3D "bla";
 string b =3D "blub";
=20
 auto res =3D doSomething(a, b);
=20
 If I didn't use "auto ref" or "ref", string would get copied, wouldn't
 it?
no, it wont -- not unless you'll append something to it. slicing arrays=20 (and string is array too) will never copy anything.=
Apr 20 2015
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Monday, 20 April 2015 at 10:14:27 UTC, Chris wrote:
 string a = "bla";
 string b = "blub";

 auto res = doSomething(a, b);

 If I didn't use "auto ref" or "ref", string would get copied, 
 wouldn't it?

 auto ref doSomething(R needle, R haystack);

 To avoid this, I would have to write a[0..$], b[0..$], which is 
 not nice. Right or wrong?
Wrong. `a[0..$]` is the same as simply `a`. A `string` is just another slice: a pointer and a length.
Apr 20 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Monday, 20 April 2015 at 10:27:00 UTC, anonymous wrote:
 On Monday, 20 April 2015 at 10:14:27 UTC, Chris wrote:
 string a = "bla";
 string b = "blub";

 auto res = doSomething(a, b);

 If I didn't use "auto ref" or "ref", string would get copied, 
 wouldn't it?

 auto ref doSomething(R needle, R haystack);

 To avoid this, I would have to write a[0..$], b[0..$], which 
 is not nice. Right or wrong?
Wrong. `a[0..$]` is the same as simply `a`. A `string` is just another slice: a pointer and a length.
Ah, I see. So strings don't get copied around and I can remove ref, very good.
Apr 20 2015
parent "Chris" <wendlec tcd.ie> writes:
On Monday, 20 April 2015 at 10:42:54 UTC, Chris wrote:
 On Monday, 20 April 2015 at 10:27:00 UTC, anonymous wrote:
 On Monday, 20 April 2015 at 10:14:27 UTC, Chris wrote:
 string a = "bla";
 string b = "blub";

 auto res = doSomething(a, b);

 If I didn't use "auto ref" or "ref", string would get copied, 
 wouldn't it?

 auto ref doSomething(R needle, R haystack);

 To avoid this, I would have to write a[0..$], b[0..$], which 
 is not nice. Right or wrong?
Wrong. `a[0..$]` is the same as simply `a`. A `string` is just another slice: a pointer and a length.
Ah, I see. So strings don't get copied around and I can remove ref, very good.
For the record. I mixed up the results there. The code executed directly in the for loop is faster than using a struct, it's also faster than using a mixin template (around 10 msecs). My apologies.
Apr 20 2015