www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [RFC] replaceInto

reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
This is proposal was dictated by a simple sudden need when designing 
with ranges in mind. It's to introduce into Phobos the idiomatic 
function replaceInto taking an output range to store the result in.

The signature revolves around:
void replace(..., Sink)(..., Sink sink)
if(... && isOutputRange!Sink)

Motivating example (std.array replace):

auto writer = stdout.lockingTextWriter; //or pick an Appender
foreach(line; stdin.byLine)
	writer.put(replace(line, "Nick", "Nicholas"));


Skiping hardcoded strings, and lockingTextWriter (it has problems) at 
the very deep level we see - what exactly? A horrible inefficiency, of 
course! There is no need to allocate space for replaced string and even 
doing it on buffer in-place risks allocation.

With proposed replaceInto:

auto writer = stdout.lockingTextWriter; //or pick an Appender
foreach(line; stdin.byLine)
	replaceInto(line, "Nick", "Nicholas", writer);

Look ma, no allocations!

Same goes for e.g. std.regex replace, coincidence, coincidence :)

P.S. A DIP 9 flashback?


-- 
Dmitry Olshansky
Mar 04 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/04/2012 09:48 PM, Dmitry Olshansky wrote:
 This is proposal was dictated by a simple sudden need when designing
 with ranges in mind. It's to introduce into Phobos the idiomatic
 function replaceInto taking an output range to store the result in.

 The signature revolves around:
 void replace(..., Sink)(..., Sink sink)
 if(... && isOutputRange!Sink)

 Motivating example (std.array replace):

 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 writer.put(replace(line, "Nick", "Nicholas"));


 Skiping hardcoded strings, and lockingTextWriter (it has problems) at
 the very deep level we see - what exactly? A horrible inefficiency, of
 course! There is no need to allocate space for replaced string and even
 doing it on buffer in-place risks allocation.

 With proposed replaceInto:

 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 replaceInto(line, "Nick", "Nicholas", writer);

 Look ma, no allocations!

 Same goes for e.g. std.regex replace, coincidence, coincidence :)

 P.S. A DIP 9 flashback?

Yes, we need this.
Mar 04 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, March 04, 2012 22:21:46 Timon Gehr wrote:
 On 03/04/2012 09:48 PM, Dmitry Olshansky wrote:
 This is proposal was dictated by a simple sudden need when designing
 with ranges in mind. It's to introduce into Phobos the idiomatic
 function replaceInto taking an output range to store the result in.
 
 The signature revolves around:
 void replace(..., Sink)(..., Sink sink)
 if(... && isOutputRange!Sink)
 
 Motivating example (std.array replace):
 
 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 writer.put(replace(line, "Nick", "Nicholas"));
 
 
 Skiping hardcoded strings, and lockingTextWriter (it has problems) at
 the very deep level we see - what exactly? A horrible inefficiency, of
 course! There is no need to allocate space for replaced string and even
 doing it on buffer in-place risks allocation.
 
 With proposed replaceInto:
 
 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 replaceInto(line, "Nick", "Nicholas", writer);
 
 Look ma, no allocations!
 
 Same goes for e.g. std.regex replace, coincidence, coincidence :)
 
 P.S. A DIP 9 flashback?

Yes, we need this.

I've been considering that we should probably add overloads which take an output range to most of the functions in std.string - and possibly a number in std.array - so that we can get that extra boost of efficiency, but I haven't gotten around to doing anything with that yet. - Jonathan M Davis
Mar 04 2012
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 05.03.2012 9:43, Jonathan M Davis wrote:
 On Sunday, March 04, 2012 22:21:46 Timon Gehr wrote:
 On 03/04/2012 09:48 PM, Dmitry Olshansky wrote:
 This is proposal was dictated by a simple sudden need when designing
 with ranges in mind. It's to introduce into Phobos the idiomatic
 function replaceInto taking an output range to store the result in.

 The signature revolves around:
 void replace(..., Sink)(..., Sink sink)
 if(...&&  isOutputRange!Sink)

 Motivating example (std.array replace):

 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 writer.put(replace(line, "Nick", "Nicholas"));


 Skiping hardcoded strings, and lockingTextWriter (it has problems) at
 the very deep level we see - what exactly? A horrible inefficiency, of
 course! There is no need to allocate space for replaced string and even
 doing it on buffer in-place risks allocation.

 With proposed replaceInto:

 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 replaceInto(line, "Nick", "Nicholas", writer);

 Look ma, no allocations!

 Same goes for e.g. std.regex replace, coincidence, coincidence :)

 P.S. A DIP 9 flashback?

Yes, we need this.

I've been considering that we should probably add overloads which take an output range to most of the functions in std.string - and possibly a number in std.array - so that we can get that extra boost of efficiency, but I haven't gotten around to doing anything with that yet.

Yes, by the looks of it there is plenty of places to apply this. One thing that I'm unclear on is should it be overloads? The problem is that e.g. the fact that replace either returns new array or nothing depending on the arguments is kind of unexpected for the reader. Not to mention that overload space was pretty crumbled, that's why I ended up with replaceInto name. -- Dmitry Olshansky
Mar 04 2012
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 05.03.2012 12:28, Jonathan M Davis wrote:
 On Monday, March 05, 2012 11:41:52 Dmitry Olshansky wrote:
 Yes, by the looks of it there is plenty of places to apply this. One
 thing that I'm unclear on is should it be overloads?
 The problem is that e.g. the fact that replace either returns new array
 or nothing depending on the arguments is kind of unexpected for the
 reader. Not to mention that overload space was pretty crumbled, that's
 why I ended up with replaceInto name.

It may be that it makes sense as overloads in some cases and not in others. But in general, if the difference is string func(string, args) becomes something like void func(string, outputRange, args)

Ah, a matter of taste... But in my mind I envision it as either: void func(outputRange, string, args); or void func(string, args, outputRange); The first one going (noticed after the fact) as analogy to C fprintf/fscanf/sprintf/sscanf vs printf/scanf. that at least makes it consistent across all functions.
 then an overload is probably good enough, since the difference is clear -
 assuming that the output range parameter doesn't cause an ambiguities that is.

That's the hard part, the ambiguities. As implementation of functions uses appender internally almost everywhere.
 But it's probably a case-by-case thing.

 - Jonathan M Davis

-- Dmitry Olshansky
Mar 06 2012
prev sibling next sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 03/04/2012 03:48 PM, Dmitry Olshansky wrote:
 This is proposal was dictated by a simple sudden need when designing
 with ranges in mind. It's to introduce into Phobos the idiomatic
 function replaceInto taking an output range to store the result in.

 The signature revolves around:
 void replace(..., Sink)(..., Sink sink)
 if(... && isOutputRange!Sink)

 Motivating example (std.array replace):

 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 writer.put(replace(line, "Nick", "Nicholas"));


 Skiping hardcoded strings, and lockingTextWriter (it has problems) at
 the very deep level we see - what exactly? A horrible inefficiency, of
 course! There is no need to allocate space for replaced string and even
 doing it on buffer in-place risks allocation.

 With proposed replaceInto:

 auto writer = stdout.lockingTextWriter; //or pick an Appender
 foreach(line; stdin.byLine)
 replaceInto(line, "Nick", "Nicholas", writer);

 Look ma, no allocations!

 Same goes for e.g. std.regex replace, coincidence, coincidence :)

 P.S. A DIP 9 flashback?

Do want!
Mar 04 2012
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, March 05, 2012 11:41:52 Dmitry Olshansky wrote:
 Yes, by the looks of it there is plenty of places to apply this. One
 thing that I'm unclear on is should it be overloads?
 The problem is that e.g. the fact that replace either returns new array
 or nothing depending on the arguments is kind of unexpected for the
 reader. Not to mention that overload space was pretty crumbled, that's
 why I ended up with replaceInto name.

It may be that it makes sense as overloads in some cases and not in others. But in general, if the difference is string func(string, args) becomes something like void func(string, outputRange, args) then an overload is probably good enough, since the difference is clear - assuming that the output range parameter doesn't cause an ambiguities that is. But it's probably a case-by-case thing. - Jonathan M Davis
Mar 05 2012