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