dmd 2.029 release

Denis Koroskin 2korden at gmail.com
Thu Apr 23 06:05:57 PDT 2009


On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam at nospam.com> wrote:

> bearophile wrote:
>> This post is mostly for Andrei.
>> I have played with D2 a bit; probably I'll need months to digest it and  
>> its new Phobos2. While I explore Phobos I'll probably post some  
>> comments/bugs around here.
>>  After reading this:
>> http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features-in-vc10-part-3.aspx
>> I have tried to write a toy implementation of it in D2 (not using  
>> Phobos2 yet):
>>  import std.stdio: writeln;
>> import std.string: format;
>>  struct Watts {
>>     int _x;
>>     int x() const { return this._x; }
>>     Joules opMul(Seconds s) {
>>         return Joules(this._x * s.x);
>>     }
>>     string toString() { return format("Watts(%s)", this._x); }
>> }
>>  struct Seconds {
>>     int _x;
>>     int x() const { return this._x; }
>>     Joules opMul(Watts w) {
>>         return Joules(this._x * w.x);
>>     }
>>     string toString() { return format("Seconds(%s)", this._x); }
>> }
>>  struct Joules {
>>     int _x;
>>     int x() const { return this._x; }
>>     string toString() { return format("Joules(%s)", this._x); }
>> }
>>  auto map(alias f, TySeq1, TySeq2)(TySeq1 a1, TySeq2 a2) {
>>     assert(a1.length == a2.length);
>>     auto result = new typeof( f(a1[0], a2[0]) )[a1.length];
>>     for (int i; i < a1.length; i++)
>>         result[i] = f(a1[i], a2[i]);
>>     return result;
>> }
>>  void main() {
>>     auto watts = [Watts(2), Watts(3), Watts(4)];
>>     writeln(watts);
>>      auto secs = [Seconds(5), Seconds(6), Seconds(7)];
>>     writeln(secs);
>>      auto result = map!( (x, y){ return x*y; } )(watts, secs);
>>     writeln(result);
>> }
>>  Few notes:
>> - Lacking struct inheritance I have duplicated code.
>> - This whole proggy is not difficult to write. It's simpler than the  
>> C++ one. But I think it's a bit less general.
>> - Here I have not used const in input arguments yet, nor the map of  
>> Phobos2.
>> - (x, y){ return x*y; } is one of the new template literals. Can I  
>> define it elsewhere, like in an alias? So far I have failed doing that.
>>  Two things to improve:
>> 1) All structs must have a default built-in opString, a good  
>> representation can be:
>> StructName(field_value1, field_value2, field_value1, ...).
>> It's not a perfect textual representation, but it's WAY better than the  
>> current one (currently it shows just the struct name).
>> (Printing the module name before the struct name is bad, most times is  
>> just noise)
>
> No!
> <rant>
> toString() is one of the most dreadful features in D. Trying to slightly  
> improve it is a waste of time -- the whole concept needs to be redone.
> It's horribly inflexible, tedious, and hugely inefficient. What more  
> could there be to hate?
>
> - the object being called has no context. It doesn't know what format is  
> desired, for example.
> - you can't emulate formatting of built-in types, NOT EVEN int! You  
> can't do left-align, pad with zeros, include + sign, display in hex.
>
> - it's got no stream concept. Every object has to create and manage its  
> own buffer, and nobody knows if anyone actually needs it.
>
> It ought to be at least as simple as:
>
> 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 allows you to use advanced formatting options

Example:

class Number {
    private int _number;
    char[] toString(string format = null, char[] buffer = null) {
        Format format = Format.Decimal;        
        switch (format) {
            case "x": format = Format.Hexademical;
            case "X": format = Format.HexademicalUpperCase;
            case "b": format = Format.Binary;
            // ...
        }

        return formatInteger(_number, format, buffer);
    }

    static char[] formatInteger(int value, Format format, char[] buffer)
    {
        // writes to buffer, resizing it
    }
}

Cons: printf-style formatting works badly with this desing.
I belive it should be dropped anyway, in favor of a more flexible .NET-style formatting:

writefln("My name is {} and I'm 0x{X} years old", Denis, 22);

// calls name.toString("", buffer) and age.toString("X", buffer)
Result: My name is Denis and I'm 0x16 years old.

Here is another example:

MyArray myArray = new MyArray(10, 20, 30);

char[1024] buffer;
string.format(buffer, "Array contents: [{{X}, }]", myArray);

// calls myArray.toString("{X}, ", buffer); which in turn calls element.toString("X", buffer) on its elements and uses ", " as a separator:
Result: Array contents: [A, 14, 1E]

No allocation involved!


More information about the Digitalmars-d-announce mailing list