Jump to page: 1 2
Thread overview
Templates: Array slices not recognized
Apr 18, 2015
Chris
Apr 18, 2015
Max Klyga
Apr 18, 2015
Chris
Apr 18, 2015
ketmar
Apr 20, 2015
Chris
Apr 20, 2015
Marc Schütz
Apr 20, 2015
Chris
Apr 20, 2015
ketmar
Apr 20, 2015
anonymous
Apr 20, 2015
Chris
Apr 20, 2015
Chris
April 18, 2015
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?
April 18, 2015
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.

April 18, 2015
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.
April 18, 2015
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?

April 20, 2015
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!
April 20, 2015
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)[]`.
April 20, 2015
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.
April 20, 2015
On Mon, 20 Apr 2015 10:14:25 +0000, 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?

no, it wont -- not unless you'll append something to it. slicing arrays (and string is array too) will never copy anything.

April 20, 2015
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.
April 20, 2015
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.
« First   ‹ Prev
1 2