Thread overview
taskPool.reduce vs algorithm.reduce
Jul 11, 2018
Dorian Haglund
Jul 11, 2018
Paul Backus
Jul 11, 2018
Timoses
Jul 19, 2018
Malte
July 11, 2018
Hi.

I'm trying to use taskPool.reduce with a delegate, for example:

import std.parallelism;

int main(string[] args)
{
  int f(int a, int b)
  {
    if (args.length > 1)
      return a+b;
    else
      return a-b;
  }

  auto res = taskPool.reduce!f([1, 2, 3]);

  return 0;
}

But it fails to compile (with gdc 8.1.0, dmd v2.081) complaining that

template instance reduce!(f) cannot use local 'f' as parameter to non-global template reduce(functions...)

The snippet above compiles with the reduce function from std.algorithm.

Is there a way to make the code compile with taskPool.reduce ?
(I don't want to write two functions and choosing one depending on args.length)

Why the interface difference between std.algorithm's reduce and taskPool.reduce ?

Best regards,

Dorian
July 11, 2018
On Wednesday, 11 July 2018 at 08:31:30 UTC, Dorian Haglund wrote:
>
> But it fails to compile (with gdc 8.1.0, dmd v2.081) complaining that
>
> template instance reduce!(f) cannot use local 'f' as parameter to non-global template reduce(functions...)

Congratulations! You've just run into issue 5710 [1], one of D's most annoying known bugs.

[1]: https://issues.dlang.org/show_bug.cgi?id=5710

> The snippet above compiles with the reduce function from std.algorithm.
>
> [...]
>
> Why the interface difference between std.algorithm's reduce and taskPool.reduce ?

std.algorithm.reduce is a free function, so it can accept delegates as template parameters. taskPool.reduce is a member function, so it can't.
July 11, 2018
On Wednesday, 11 July 2018 at 08:31:30 UTC, Dorian Haglund wrote:
> Hi.
>
> I'm trying to use taskPool.reduce with a delegate, for example:
>
> import std.parallelism;
>
> int main(string[] args)
> {
>   int f(int a, int b)
>   {
>     if (args.length > 1)
>       return a+b;
>     else
>       return a-b;
>   }
>
>   auto res = taskPool.reduce!f([1, 2, 3]);
>
>   return 0;
> }
>
> But it fails to compile (with gdc 8.1.0, dmd v2.081) complaining that
>
> template instance reduce!(f) cannot use local 'f' as parameter to non-global template reduce(functions...)
>
> The snippet above compiles with the reduce function from std.algorithm.
>
> Is there a way to make the code compile with taskPool.reduce ?
> (I don't want to write two functions and choosing one depending on args.length)
>
> Why the interface difference between std.algorithm's reduce and taskPool.reduce ?
>
> Best regards,
>
> Dorian

As the error message says taskPool.reduce is a non-global template. It's embedded in a taskPool struct. I can't say what the reason is that a delegate cannot be used with such a template. I'd be interested in hearing what the reason is.
(See Paul's reply).

I'm trying to trick around it, but can't get this to work...

https://run.dlang.io/is/EGbtuq

import std.parallelism;

int main(string[] args)
{
    static int f(bool cond)(int a, int b)
    {
        static if (cond)
            return a+b;
        else
            return a-b;
    }

    template getF(alias func)
    {
        auto getF(T)(T arg)
        {
            if (args.length > 1)
                return func!(f!true)(arg); // line 18
            else
                return func!(f!false)(arg); // line 20
        }
    }

    auto res = getF!(taskPool.reduce)([1,2,3]);

    return 0;
}


onlineapp.d(18): Error: need this for reduce of type @system int(int[] _param_0)
onlineapp.d(20): Error: need this for reduce of type @system int(int[] _param_0)
July 19, 2018
On Wednesday, 11 July 2018 at 10:07:33 UTC, Timoses wrote:
> On Wednesday, 11 July 2018 at 08:31:30 UTC, Dorian Haglund wrote:
>> [...]
>
> As the error message says taskPool.reduce is a non-global template. It's embedded in a taskPool struct. I can't say what the reason is that a delegate cannot be used with such a template. I'd be interested in hearing what the reason is.
> (See Paul's reply).
>
> I'm trying to trick around it, but can't get this to work...
>
> https://run.dlang.io/is/EGbtuq

You can make it all global: https://run.dlang.io/is/Kf8CLC

From my own experience: Use only parallel foreach and save yourself a lot of hassle. That just works.