redefining "put" and "OutputRange"

monarch_dodra monarchdodra at gmail.com
Fri Aug 30 03:53:37 PDT 2013


I'm starting this thread, first, as a shamless plug to a brand 
new pull I just did, which (amongst others) allows "put" to 
transcode on the fly any string/char of any length, to any 
string/char of any length.

This fixes issues mostly in std.format, and also allows things 
like formattedWrite to work with pure delegates (it didn't 
before), as well as output directly in wstring or dstring format 
(awesome for writing to a UTF-16 file, for example).

--------

The real reason I'm starting this thread is I believe the current 
way "put" leads to a *MASSIVE*, *HORRIFYING* issue. I dare not 
say it: Escaping references to local stack variables (!!!).

Basically, if R accepts an "E[]", than put will accept a single E 
element as input, and convert it to an "E[]" on the fly, using 
"put(r, (&e)[0 .. 1]);". I'm sure you can see the problem. It 
allows things such as:

//----
void main()
{
     Appender!(int[][]) app; //A type that accumulates slices
     put(app, 1);
     put(app, 2);
     put(app, 3);
     writeln(app.data); //prints: [[3], [3], [3]]
}
//----
Oops!

I'd like to make a proposition: "put" needs to be changed to 
*not* accept putting an E into something that accepts E[]. There 
is simply *no way* to do this safely, and without allocating 
(both of which, IMO, are non-negotiable).

For objects that define put/opCall, then it is not very 
complicated to have two different signatures for 
"put(E[])"/"opCall(E[])" *and* "put(E)"/"opCall(E)". This makes 
it explicit what is and isn't accepted.

Lucky enough, the problem never existed with input ranges: 
"int[][]" never accepted "int", so there is no problem there.

The last thing remaining are "sinks" (delegates and functions). 
As a convenience, and *only* for characters sinks, because we 
*trust* them to make local copies of elements, we can allow 
things like:
put((const(char)[]){}, 'a');// OK
put((const(char)[]){}, '本');// OK
put((const(char)[]){}, "hello"d);// OK
put((const(wchar)[]){}, "hello"c);// OK

This, I think, is what is safest, but still leaves a little open 
door, exceptionally, for easy formatting.

--------

So, the idea is now to yay or nay my change proposal, and/or 
discuss my pull:
https://github.com/D-Programming-Language/phobos/pull/1534


More information about the Digitalmars-d mailing list