Thread overview
Deciding one member of iteration chain at runtime
Feb 17, 2023
Chris Piker
Feb 17, 2023
Ali Çehreli
Feb 17, 2023
Chris Piker
Feb 17, 2023
H. S. Teoh
Feb 17, 2023
Chris Piker
February 17, 2023

Hi D

I have a main "loop" for a data processing program that looks much as follows:

sourceRange
  .operatorA
  .operatorB
  .operatorC
  .operatorD
  .operatorE
  .operatorF
  .operatorG
  .operatorH
  .copy(destination);

Where all operator items above are InputRange structs that take an upstream range, and the pipeline really is 9 operations deep.

In order to handle new functionality it turns out that operatorG needs to be of one of two different types at runtime. How would I do something like the following:

auto virtualG;  // <-- probably invalid code, illustrating the idea
if(runtime_condition)
   virtualG = operatorG1;
else
   virtualG = operatorG2;

sourceRange
  .operatorA
  .operatorB
  .operatorC
  .operatorD
  .operatorE
  .operatorF
  .virtualG
  .operatorH
  .copy(destination);

?

I've tried various usages of range.InputRangeObject but haven't been able to get the syntax right. Any suggestions on the best way to proceed? Maybe the whole chain should be wrapped in InputRangeObject classes, I don't know.

Thanks,

February 17, 2023
On 2/17/23 09:30, Chris Piker wrote:

> operatorG needs
> to be of one of two different types at runtime

std.range.choose may be useful but I think it requires creating two variables like g1 and g2 below:

import std.range;
import std.algorithm;

void main(string[] args) {
    const condition = (args.length > 1);

    // The first part of the algorithm
    auto r = iota(10)
             .filter!(n => n % 2);

    // Two different steps
    auto g1 = r.map!((int n) => n * n);
    auto g2 = r.map!((int n) => n * 10);

    // The rest of the algoritm
    auto result = choose(condition, g1, g2)
                  .array;
}

Ali

February 17, 2023
On Fri, Feb 17, 2023 at 05:30:40PM +0000, Chris Piker via Digitalmars-d-learn wrote: [...]
> In order to handle new functionality it turns out that operatorG needs to be of one of two different types at runtime.  How would I do something like the following:
> 
> ```d
> auto virtualG;  // <-- probably invalid code, illustrating the idea
> if(runtime_condition)
>    virtualG = operatorG1;
> else
>    virtualG = operatorG2;
[...]
> ```
> ?
> 
> I've tried various usages of `range.InputRangeObject` but haven't been able to get the syntax right.  Any suggestions on the best way to proceed?  Maybe the whole chain should be wrapped in InputRangeObject classes, I don't know.
[...]

Here's an actual function taken from my own code, that returns a different range type depending on a runtime condition, maybe this will help you?

```d
/**
 * Expands '@'-directives in a range of strings.
 *
 * Returns: A range of strings with lines that begin with '@'
 * substituted with the contents of the file named by the rest of the
 * line.
 */
auto expandFileDirectives(File = std.stdio.File, R)(R args)
    if (isInputRange!R && is(ElementType!R : const(char)[]))
{
    import std.algorithm.iteration : joiner, map;
    import std.algorithm.searching : startsWith;
    import std.range : only;
    import std.range.interfaces : InputRange, inputRangeObject;
    import std.typecons : No;

    return args.map!(arg => arg.startsWith('@') ?
                    cast(InputRange!string) inputRangeObject(
                        File(arg[1 .. $]).byLineCopy(No.keepTerminator)) :
                    cast(InputRange!string) inputRangeObject(only(arg)))
               .joiner;
}
```

Note that the cast is to a common base class of the two different subclasses returned by inputRangeObject().

This function is used in the rest of the code as part of a UFCS chain of ranges.


T

-- 
Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".
February 17, 2023
On Friday, 17 February 2023 at 17:44:20 UTC, H. S. Teoh wrote:
> Here's an actual function taken from my own code, that returns a different range type depending on a runtime condition, maybe this will help you?

Thanks, this was helpful.

I keep forgetting to expand my horizons on what can be returned from an auto function.  I'm still unlearning C & Java.

Cheers,


February 17, 2023
On Friday, 17 February 2023 at 17:42:19 UTC, Ali Çehreli wrote:
>     // Two different steps
>     auto g1 = r.map!((int n) => n * n);
>     auto g2 = r.map!((int n) => n * 10);
>
>     // The rest of the algoritm
>     auto result = choose(condition, g1, g2)
>                   .array;

Now that's a handy construct.

There's many little goodies in phobos I've yet to learn, thanks for the tip!