Why is there no lazy `format`?

burt invalid_email_address at cab.abc
Tue Oct 20 18:24:01 UTC 2020


On Tuesday, 20 October 2020 at 18:03:32 UTC, H. S. Teoh wrote:
> [...]
>
> Yeah, I think std.format's design isn't really conducive to 
> lazy access. Also, the way the OP wrote the example code isn't 
> really consistent, because it appears to be returning segments 
> of the formatted string rather than characters in the string, 
> i.e., it behaves like `string[]` rather than `string`, which 
> isn't how std.format is designed to work.

Well, the idea was that you could call `join()` or `flatten()` or 
whatever it is called to turn it into an input range of chars. 
But it could also do that directly.

I understand now why returning an input range could be 
problematic though.

> [...]
> What *would* be nice, is a standard library construct for 
> inverting an output range into an input range. Fibers is one 
> way of doing this. Basically, the pipeline up to the output 
> range will run in its own fiber, and initially it's 
> backgrounded. As data is requested from the input range end of 
> the interface, it will context-switch to the output range fiber 
> and generate data which gets saved into a buffer. At some point 
> calling Fiber.yield(); then the input range end will start 
> spooling the generated data to the caller.  Once the buffered 
> data is exhausted, it context-switches to the output range 
> fiber again, etc..
>
> Note that this does not alleviate the need for buffering, and 
> it's not 100% lazy; what it primarily does is to give a nice 
> input range interface for stuff written into an output range.  
> I don't expect it will do very well performance-wise either, 
> unless the data generators are designed to cooperate with the 
> inverter -- but in that case, they would have been written to 
> return an input range instead of requiring an output range in 
> the first place. So this construct is really more for 
> convenience than anything.

Interesting idea. Although maybe it doesn't even have to use 
fibers to work, if you're willing to give up the laziness part:

```
/*ref*/ O pipeRange(alias fn, O, T...)(/*ref*/ O output, T args)
if (isInputRange!O && isOutputRange!O)
{
     fn(output, args);
     return output;
}

auto thing = appender!string()
     .pipeRange!formattedWrite("%d plus %d is %d", 1, 2, 3)
     .map!toUpperCase()
     .array();
```

Or something like that.


More information about the Digitalmars-d mailing list