"Steven Schveighoffer" <[email protected]> wrote in message news:[email protected]... >A recent bug report reminded me of how horrible D is at printing custom >types. > > Consider a container type that contains 1000 elements, such as a linked > list. If you print this type, you would expect to get a printout similar > to an array, i.e.: > > [ 1 2 3 4 5 ... 1000 ] > > If you do this: > > writeln(mylist); > > then what happens is, writeln calls mylist.toString(), and prints that > string. > > But inside mylist.toString, it likely does things like elem[0].toString() > and concatenates all these together. This results in at least 1000 + 1 > heap allocations, to go along with 1000 appends, to create a string that > will be sent to an output stream and *discarded*. > > So the seemingly innocuous line writeln(mylist) is like attaching a boat > anchor to your code performance. > > There is a better way, as demonstrated by BigInt (whose author refuses to > implement toString()): > > void toString(scope void delegate(scope const(char)[] data), string format > = null) > > What does this do? Well, now, writeln can define a delegate that takes a > string and sends it to an output stream. Now, there is no copying of > data, no heap allocations, and no need to concatenate anything together! > Not only that, but it can be given an optional format specifier to control > output when writefln is used. Let's see how a linked list would implement > this function (ignoring format for now): > > void toString(scope void delegate(scope const(char)[] data) sink, string > format = null) > { > sink("["); > foreach(elem; this) > { > sink(" "); > elem.toString(sink); > } > sink(" ]"); > } > > It looks just about as simple as the equivalent function that would > currently be necessary, except you have *no* heap allocations, there is a > possibility for formatting, and D will be that much better performing. > Note that using a delegate allows much more natural code which requires > recursion. > > Should we create a DIP for this? I'll volunteer to spearhead the effort > if people are on board. >
I like it, *provided that* there's a quick-and-easy way to just get a string when that's all you want. At the very least there should be a standard sink function that's a default argument to toString that just simply builds a string. What we definitely *don't* want is for the user to ever have to write their own sink delegate just to get a string (which I've had to do with Tango on occasion).
