dmd 2.029 release

Denis Koroskin 2korden at gmail.com
Thu Apr 23 07:04:27 PDT 2009


On Thu, 23 Apr 2009 17:35:59 +0400, Frits van Bommel <fvbommel at remwovexcapss.nl> wrote:

> Denis Koroskin wrote:
>> On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam at nospam.com> wrote:
>>
>>> struct Foo(A, B, C){
>>> A[10] a;
>>> B b;
>>> C c;
>>> void toString(Sink sink){
>>>     foreach(x; a) sink(x);
>>>     sink(b);
>>>     sink(c);
>>> }
>>> }
>>> ... but it's not, you have to create a silly buffer to put all your   
>>> strings in, even if there are 200 million of them and your giant  
>>> string  is just going to be written to a file anyway.
>>>
>>  Absolutely agree, but Sink is not good, either. I have previously  
>> suggested the following design (but can't find my post anymore):
>>  A signature of toString() should be as follows:
>>  char[] toString(string format = null, char[] buffer = null);
>>  Bonuses you get from that:
>> You don't have to change your code (aside from toString() returning  
>> mutable array now, but it is very easy to fix)
>> It allows you to avoid allocations - just pass a temporary buffer to  
>> use!
>
> It'll still allocate if the buffer isn't big enough.
>

Of course, it allows you to avoid allocations, but it doesn't necessarily eliminate them.

> I usually define something like "void streamTo(Sink sink)" in a base  
> class if I want non-allocating output. Adding a format string to the  
> parameter list should be easy, but I haven't needed it yet.
> I then usually implement toString by passing an appending Sink to that  
> method, just so Tango's formatting methods will be able to use it.
>
>
>
> IMHO It'd be pretty nice for the standard formatting systems (both the  
> Tango and Phobos ones) to just call a standard Object method taking  
> (Sink sink, char[] format = null) on objects.
>

Sink is okay, but most my usages belong to one of the two scenarios:
1) I need a string representation of an Object - how is Sink useful here? I just want to call obj.toString() and get the result
2) I need to print it to stdout, thus I call writeln/Stdout(obj); - Sink is of no use here again.

That said, I have other use-cases, too, but never once I needed a custom Sink property.
Besides, having a Sink object is redundant and makes things more complex in most cases. Compare:

class Number
{
    private int _number;

    // My version
    char[] toString(string format, char[] buffer = null) {
        return std.string.format(buffer, format, _number); // use default formatter, buffer is provided to avoid allocations
    }

    // Your version
    void toString(Sink sink, string format = null) {
        // what should I do here? How do I avoid allocations? I have to duplicate code anyway
        char[16] buffer;
        buffer = std.string.format(buffer, format, _number);
        sink(buffer);
    }
}

How is that better than using external sink? Use composition! toString/streamOut can be implemented on top of my toString:

char[] buffer;
sink(object.toString(format, buffer)); // I believe explicit is better here

Also, this way sink is called directly an may be inlined.

Besides, why is it called toString(), if it doesn't give me an object's string representation???

> Backward compatibility might be tricky though, if you want to support  
> both overriding and calling of toString(). (You can't have the default  
> toString implementation call the format function *and* have the default  
> format function implementation call toString)
>

My version is (almost) backwards compatible.


More information about the Digitalmars-d-announce mailing list