Bug 9882 – Add UFCS-friendly printing functions

Status
RESOLVED
Resolution
WORKSFORME
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-04-05T05:27:08Z
Last change time
2017-08-26T17:31:13Z
Assigned to
No Owner
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2013-04-05T05:27:08Z
This program prints the transposed of some strings. You can see that if you want to print the result of a long UFCS chain with a formatting string you are forced to break the chain, and it's not immediate to print intermediate steps: import std.stdio: writeln, writefln; import std.range: iota, transversal; import std.algorithm: map, reduce, max; void main() { immutable txt = ["Line one", "Line 2"]; writefln("%(%s\n%)", txt .map!q{ a.length } .map!((s){ writeln(s); return s; }) .reduce!max .iota .map!(i => txt.transversal(i))); } Output: 8 6 LL ii nn ee o2 n e - - - - - - - - - - - - - - - - - - - - - - - A simple way to solve both problems is to add to std.stdio four printing functions that are UFCS-friendly, where the format string is leading: import std.stdio: write, writeln, writef, writefln; import std.traits: isSomeString; auto uWrite(T)(T data) { write(data); return data; } auto uWriteln(T)(T data) { writeln(data); return data; } auto uWritef(T, TS)(T data, TS format) if (isSomeString!TS) { writef(format, data); return data; } auto uWritefln(T, TS)(T data, TS format) if (isSomeString!TS) { writefln(format, data); return data; } // Usage demo ------------- import std.range: iota, transversal; import std.algorithm: map, reduce, max; void main() { immutable txt = ["Line one", "Line 2"]; txt .map!q{ a.length } .uWriteln .reduce!max .iota .map!(i => txt.transversal(i)) .uWritefln("%(%s\n%)"); } Output (also note that 8 and 6 are printed with the array syntax): [8, 6] LL ii nn ee o2 n e - - - - - - - - - - - - - - - - - - - - - - - Disadvantages: 1) A .tap() function that allows to perform some impure operation on the stream, but keep it flowing, is more general than those printing functions. Something like this: import std.range: iota, transversal; import std.algorithm: map, reduce, max; import std.range: tap; void main() { immutable txt = ["Line one", "Line 2"]; txt .map!q{ a.length } .tap!q{ writeln(s) } .reduce!max .iota .map!(i => txt.transversal(i)) .tap!q{ writefln("%(%s\n%)", s) }; } In practice I've seen that in most cases I such tap only to print. 2) functions like that uWritefln() accept only the format string beside the stream to print. So you can't print the stream plus some other data. In theory this can be solved with printing functions like this: auto uWrite(TArgs...)(TArgs items) { write(items); return items[0]; } auto uWriteln(TArgs...)(TArgs items) { writeln(items); return items[0]; } auto uWritef(TArgs...)(TArgs items) if (isSomeString!(TArgs[$ - 1])) { writef(items[$ - 1], items[0 .. $ - 1]); return items[0]; } auto uWritefln(TArgs...)(TArgs items) if (isSomeString!(TArgs[$ - 1])) { writefln(items[$ - 1], items[0 .. $ - 1]); return items[0]; } But their order of printing is not intuitive, so I suggest to not use them. See also the discussion thread: http://forum.dlang.org/thread/[email protected]
Comment #1 by doob — 2013-04-05T08:22:48Z
I like that "tap" function in Ruby and use it for non-range code as well.
Comment #2 by bearophile_hugs — 2013-04-05T11:02:48Z
(In reply to comment #1) > I like that "tap" function in Ruby and use it for non-range code as well. To use tap I have used a syntax like: .tap!q{ writeln(s) } .tap!q{ writefln("%(%s\n%)", s) }; But I don't know if such syntax is good and possible in D.
Comment #3 by doob — 2013-04-05T11:46:00Z
> To use tap I have used a syntax like: > > .tap!q{ writeln(s) } > .tap!q{ writefln("%(%s\n%)", s) }; > > But I don't know if such syntax is good and possible in D. Sure, but I prefer the lambda syntax: .tap!(s => writeln(s))
Comment #4 by bearophile_hugs — 2013-04-05T11:52:25Z
(In reply to comment #3) > Sure, but I prefer the lambda syntax: > > .tap!(s => writeln(s)) A lambda like s => writeln(s) returns void, it's kind of the opposite of the lambda calculus :-)
Comment #5 by doob — 2013-04-05T12:00:05Z
(In reply to comment #4) > A lambda like s => writeln(s) returns void, it's kind of the opposite of the > lambda calculus :-) Right, forgot that.
Comment #6 by bearophile_hugs — 2013-04-26T15:28:37Z
A suggestion in D.learn shows me that sometimes std.functional.binaryReverseArgs is an acceptable solution for the terminal writefln (but it can't be used for intermediate printing): import std.stdio: writeln, writefln; import std.range: iota, transversal; import std.algorithm: map, reduce, max; import std.functional: binaryReverseArgs; void main() { immutable txt = ["Line one", "Line 2"]; txt .map!q{ a.length } .map!((s){ s.writeln; return s; }) .reduce!max .iota .map!(i => txt.transversal(i)) .binaryReverseArgs!writefln("%(%s\n%)"); }
Comment #7 by github-bugzilla — 2014-07-16T16:56:28Z
Commits pushed to master at https://github.com/D-Programming-Language/phobos https://github.com/D-Programming-Language/phobos/commit/45c4e51982c47e0f76583459eeb47a830c0277a1 Revive #1348: "Issue 9882 - Implement a "tee" style InputRange so that a function can be called during a chain of InputRanges." https://github.com/D-Programming-Language/phobos/commit/6d5ab305b9397da1098ba03fd0f2bc453150a0ef Merge pull request #1965 from MetaLang/std-range-tee-fixup Revive pull request #1348: "Issue 9882 - Implement a "tee" style InputRange...
Comment #8 by bearophile_hugs — 2014-07-16T17:28:44Z
(In reply to github-bugzilla from comment #7) > Commits pushed to master at https://github.com/D-Programming-Language/phobos > > https://github.com/D-Programming-Language/phobos/commit/ > 45c4e51982c47e0f76583459eeb47a830c0277a1 > Revive #1348: "Issue 9882 - Implement a "tee" style InputRange so that a > function can be called during a chain of InputRanges." > > https://github.com/D-Programming-Language/phobos/commit/ > 6d5ab305b9397da1098ba03fd0f2bc453150a0ef > Merge pull request #1965 from MetaLang/std-range-tee-fixup > > Revive pull request #1348: "Issue 9882 - Implement a "tee" style > InputRange... Was this comment a mistake? This merge is about tee, it's not about a UFCS-friendly printing function like uWritefln :-)
Comment #9 by b2.temp — 2017-08-26T17:31:13Z
std.range.tee was added.