Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
January 22, 2017 Output range and writeln style functions | ||||
---|---|---|---|---|
| ||||
I've been increasingly using output ranges in my code (the "component programming" model described in several articles on the D site). It works very well, except that it would often be more convenient to use writeln style functions rather than 'put'. Especially when you start by drafting a sketch of code using writeln functions, then convert it an output range. Seems an obvious thing, I'm wondering if I missed something. Are there ways to use writeln style functions with output ranges? --Jon |
January 23, 2017 Re: Output range and writeln style functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jon Degenhardt | On 01/22/2017 01:54 PM, Jon Degenhardt wrote: > I've been increasingly using output ranges in my code (the "component > programming" model described in several articles on the D site). It > works very well, except that it would often be more convenient to use > writeln style functions rather than 'put'. Especially when you start by > drafting a sketch of code using writeln functions, then convert it an > output range. > > Seems an obvious thing, I'm wondering if I missed something. Are there > ways to use writeln style functions with output ranges? > > --Jon I don't think I understand the question. :) If you need a variadic put(), then I've come up with the following mildly tested AllAppender. Just as a reminder, I've also used std.range.tee that allows tapping into the stream to see what's flying through: import std.array : Appender, appender; import std.stdio : writeln; struct AllAppender(T) { Appender!T app; alias app this; void put(Args...)(Args args) { foreach (arg; args) { static if (__traits(compiles, app.put(arg))) { app.put(arg); } else { import std.conv : to; app.put(arg.to!T); } } } } import std.range : isOutputRange; static assert(isOutputRange!(AllAppender!string, int)); static assert(isOutputRange!(AllAppender!string, double)); auto allAppender(T)() { return AllAppender!T(); } void main() { auto a = allAppender!string(); a.put(1, "hello"); import std.range : tee; import std.algorithm : copy; [ 10, 20, 30 ] .tee!(e => writeln("appending ", e)) .copy(a); writeln(a.data); } Ali |
January 23, 2017 Re: Output range and writeln style functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Monday, 23 January 2017 at 08:03:14 UTC, Ali Çehreli wrote:
> On 01/22/2017 01:54 PM, Jon Degenhardt wrote:
>> I've been increasingly using output ranges in my code (the "component
>> programming" model described in several articles on the D site). It
>> works very well, except that it would often be more convenient to use
>> writeln style functions rather than 'put'. Especially when you start by
>> drafting a sketch of code using writeln functions, then convert it an
>> output range.
>>
>> Seems an obvious thing, I'm wondering if I missed something. Are there
>> ways to use writeln style functions with output ranges?
>>
>> --Jon
>
> I don't think I understand the question. :)
>
> If you need a variadic put(), then I've come up with the following mildly tested AllAppender. Just as a reminder, I've also used std.range.tee that allows tapping into the stream to see what's flying through:
>
> [snip]
>
> Ali
So I guess the is answer is "no" :)
It's mainly about consistency of the output primitives. Includes variadic args, formatting, and names of the primitives. I keep finding myself starting with something like:
void writeLuckyNumber(string name, int luckyNumber)
{
writefln("Hello %s, your lucky number is %d", name, luckyNumber);
}
and then re-factoring it as:
void writeLuckyNumber(OutputRange)
(OutputRange outputStream, string name, int luckyNumber)
if (isOutputRange!(OutputRange, char))
{
import std.format;
outputStream.put(
format("Hello %s, your lucky number is %d\n", name, luckyNumber));
}
Not bad, but the actual output statements are a bit harder to read, especially if people reading your code are not familiar with output ranges. So, what I'm really wondering is if there is built-in way to get closer to:
outputStream.writefln(...);
that I've overlooked.
--Jon
|
January 23, 2017 Re: Output range and writeln style functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jon Degenhardt | On 01/23/2017 12:48 PM, Jon Degenhardt wrote: > On Monday, 23 January 2017 at 08:03:14 UTC, Ali Çehreli wrote: >> On 01/22/2017 01:54 PM, Jon Degenhardt wrote: >>> I've been increasingly using output ranges in my code (the "component >>> programming" model described in several articles on the D site). It >>> works very well, except that it would often be more convenient to use >>> writeln style functions rather than 'put'. Especially when you start by >>> drafting a sketch of code using writeln functions, then convert it an >>> output range. >>> >>> Seems an obvious thing, I'm wondering if I missed something. Are there >>> ways to use writeln style functions with output ranges? >>> >>> --Jon >> >> I don't think I understand the question. :) >> >> If you need a variadic put(), then I've come up with the following >> mildly tested AllAppender. Just as a reminder, I've also used >> std.range.tee that allows tapping into the stream to see what's flying >> through: >> >> [snip] >> >> Ali > > So I guess the is answer is "no" :) > > It's mainly about consistency of the output primitives. Includes > variadic args, formatting, and names of the primitives. I keep finding > myself starting with something like: > > void writeLuckyNumber(string name, int luckyNumber) > { > writefln("Hello %s, your lucky number is %d", name, luckyNumber); > } > > and then re-factoring it as: > > void writeLuckyNumber(OutputRange) > (OutputRange outputStream, string name, int luckyNumber) > if (isOutputRange!(OutputRange, char)) > { > import std.format; > outputStream.put( > format("Hello %s, your lucky number is %d\n", name, > luckyNumber)); > } > > Not bad, but the actual output statements are a bit harder to read, > especially if people reading your code are not familiar with output > ranges. So, what I'm really wondering is if there is built-in way to get > closer to: > > outputStream.writefln(...); > > that I've overlooked. > > > --Jon If it's about formatted output then perhaps formattedWrite? https://dlang.org/phobos/std_format.html#.formattedWrite The same function is used with stdout and an Appender: import std.stdio; import std.range; void writeLuckyNumber(OutputRange) (OutputRange outputStream, string name, int luckyNumber) if (isOutputRange!(OutputRange, char)) { import std.format : formattedWrite; formattedWrite(outputStream, "Hello %s, your lucky number is %d\n", name, luckyNumber); } void main() { writeLuckyNumber(stdout.lockingTextWriter, "Jon", 42); auto app = appender!string(); writeLuckyNumber(app, "Jon", 42); writeln(app.data); } Ali |
January 23, 2017 Re: Output range and writeln style functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Monday, 23 January 2017 at 22:20:59 UTC, Ali Çehreli wrote:
> On 01/23/2017 12:48 PM, Jon Degenhardt wrote:
> [snip]
> > So, what I'm really wondering is if there is built-in way
>> to get closer to:
>>
>> outputStream.writefln(...);
>>
>
> If it's about formatted output then perhaps formattedWrite?
>
> https://dlang.org/phobos/std_format.html#.formattedWrite
>
> The same function is used with stdout and an Appender:
>
> [snip]
>
> Ali
Oh, that is better, thanks!
--Jon
|
Copyright © 1999-2021 by the D Language Foundation