Useful Workarounds

From D Wiki
Jump to: navigation, search

It is sometimes necessary to find workarounds to bugs, compiler limitations and language design issues.

Some common use-cases which require workarounds are:

std.parallelism amap & reduce

Due to Issue 5710, you cannot use delegates with amap and reduce. This essentially limits amap & reduce to taking free functions as template parameters.

amap

The workaround for amap is to replace:

import std.parallelism;
auto result = taskPool.amap!(myDelegate)(inputRange);

With:

import std.range: chunks, zip;
import std.parallelism;
auto result = new ResultType[inputRange.length];
auto chunkSize = taskPool.defaultWorkUnitSize(inputRange.length);
auto inputChunks = inputRange.chunks(chunkSize);
auto outputChunks = result.chunks(chunkSize);
foreach (ioChunk; outputChunks.zip(inputChunks).parallel(1))
{
    auto inputChunk = ioChunk[1];
    auto outputChunk = ioChunk[0];
    foreach (i,input; inputChunk)
       outputChunk[i] = myDelegate(input);
}

Where "ResultType" is the return type of "myDelegate."

A less powerful, more efficient alternative is:

import std.range;
import std.traits;
import std.typecons;
import std.parallelism;

static auto magic(T)(T tup)
	if (isTuple!T && isCallable!(typeof(tup[0])) && T.Types.length > 1)
{
	return tup[0](tup[1 ..$]);
}

static auto magicInput(D,R...)(D d, R r)
	if (isCallable!D && allSatisfy!(isRandomAccessRange,R))
{
	return repeat(d, zip(r).length).zip(r);
}

auto result = taskPool.amap!(magic)(magicInput(myDelegate,inputRange));

reduce

The workaround for reduce is to replace:

import std.parallelism;
auto result = taskPool.reduce!(myDelegate)(seed,inputRange);

With:

import std.range : chunks, frontTransversal, zip;
import std.algorithm : reduce;
import std.parallelism;
auto chunkSize = taskPool.defaultWorkUnitSize(inputRange.length);
auto inputChunks = inputRange.chunks(chunkSize);
auto partialResults = (new ResultType[inputChunks.length]).chunks(1);
foreach (ioChunk; partialResults.zip(inputChunks).parallel(1))
{
    auto inputChunk = ioChunk[1];
    auto partialResult = ioChunk[0];
    partialResult[0] = reduce!(myDelegate)(seed, inputChunk);
}
auto result = partialResults.frontTransversal.reduce!(myDelegate);

Where "ResultType" is the return type of "myDelegate."