Jump to page: 1 28  
Page
Thread overview
Re: dmd 2.029 release
Apr 23, 2009
bearophile
Apr 23, 2009
Don
Apr 23, 2009
grauzone
Apr 23, 2009
Simen Kjaeraas
Apr 23, 2009
Denis Koroskin
Apr 23, 2009
Frits van Bommel
Apr 23, 2009
Frits van Bommel
Apr 23, 2009
Denis Koroskin
Apr 23, 2009
grauzone
Apr 23, 2009
Denis Koroskin
Apr 23, 2009
grauzone
Apr 23, 2009
grauzone
Apr 23, 2009
grauzone
Apr 24, 2009
Simen Kjaeraas
Apr 24, 2009
grauzone
Apr 24, 2009
grauzone
Apr 24, 2009
Christopher Wright
Apr 23, 2009
Daniel Keep
Apr 23, 2009
Frits van Bommel
Apr 23, 2009
Christopher Wright
Apr 23, 2009
Georg Wrede
Apr 23, 2009
Georg Wrede
Apr 23, 2009
Georg Wrede
Apr 23, 2009
Don
Apr 23, 2009
Georg Wrede
Apr 23, 2009
Don
Apr 23, 2009
Georg Wrede
Apr 23, 2009
Don
Apr 23, 2009
Georg Wrede
Apr 23, 2009
Joel C. Salomon
Re: dmd 2.029 release [OT]
Apr 23, 2009
Georg Wrede
Apr 24, 2009
Georg Wrede
Apr 24, 2009
Nick Sabalausky
Apr 24, 2009
Georg Wrede
Apr 28, 2009
Benji Smith
Apr 24, 2009
Nick Sabalausky
Apr 24, 2009
Christopher Wright
Apr 24, 2009
Jesse Phillips
Apr 24, 2009
BCS
Apr 24, 2009
Daniel Keep
Apr 24, 2009
Nick Sabalausky
Apr 24, 2009
Denis Koroskin
Apr 24, 2009
BCS
Apr 24, 2009
Nick Sabalausky
Apr 24, 2009
BCS
Apr 24, 2009
Christopher Wright
Apr 24, 2009
BCS
Apr 25, 2009
Nick Sabalausky
Apr 25, 2009
BCS
Apr 24, 2009
Georg Wrede
Apr 24, 2009
grauzone
Apr 24, 2009
Georg Wrede
Apr 24, 2009
Georg Wrede
Apr 24, 2009
Nick Sabalausky
Apr 24, 2009
Georg Wrede
Apr 23, 2009
Denis Koroskin
April 23, 2009
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)

2) The output of that program is:
Watts(2) Watts(3) Watts(4)
Seconds(5) Seconds(6) Seconds(7)
Joules(10) Joules(18) Joules(28)

I think a much better output is:
[Watts(2), Watts(3), Watts(4)]
[Seconds(5),  Seconds(6),  Seconds(7)]
[Joules(10),  Joules(18),  Joules(28)]

Note the space after the comma, it's a small detail but it improves readability significantly. (This representation doesn't tell apart dynamic arrays from static ones, but I can live with this).

----------------

I don't remember if vector ops support user-defined opMul too, I have tried this code, but maybe I am doing something wrong:

...
    Joules[3] result2;
    result2[] = watts[] * secs[];
    writeln(result2);
}

Bye,
bearophile
April 23, 2009
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.

I'd like to see version(debug) {} put around Object.toString(). It's a deathtrap feature that's got no business being used other than for debugging.
</rant>


> 
> 2) The output of that program is:
> Watts(2) Watts(3) Watts(4)
> Seconds(5) Seconds(6) Seconds(7)
> Joules(10) Joules(18) Joules(28)
> 
> I think a much better output is:
> [Watts(2), Watts(3), Watts(4)]
> [Seconds(5),  Seconds(6),  Seconds(7)]
> [Joules(10),  Joules(18),  Joules(28)]
> 
> Note the space after the comma, it's a small detail but it improves readability significantly.
> (This representation doesn't tell apart dynamic arrays from static ones, but I can live with this).
> 
> ----------------
> 
> I don't remember if vector ops support user-defined opMul too, I have tried this code, but maybe I am doing something wrong:
> 
> ...
>     Joules[3] result2;
>     result2[] = watts[] * secs[];
>     writeln(result2);
> }
> 
> Bye,
> bearophile
April 23, 2009
> 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?

Hey, it's only meant for debugging! (At least I hope.)
April 23, 2009
Don wrote:

> I'd like to see version(debug) {} put around Object.toString(). It's a deathtrap feature that's got no business being used other than for debugging.

That actually sounds like a good idea. Like you say, is has no use
outside of debugging, but while debugging, it's quite useful.

--
 Simen
April 23, 2009
On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam@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!
April 23, 2009
Don wrote:
> 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?

I agree.

> - 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.

Yah. std.stdio and std.format already uses streaming internally to some extent. I plan to make it entirely possible to dump a string and a binary representation of an object to a generic stream, without having to allocate any memory in the process.

> 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.

Yes. The way it should be is not with sink, but with the standard output iterator method put().

void streamOut(T, R)(T object, R range)
{
    foreach(x; a) range.put(x);
    range.put(b);
    range.put(c);
}

> I'd like to see version(debug) {} put around Object.toString(). It's a deathtrap feature that's got no business being used other than for debugging.

Well toString is ok for casual uses, but I agree that true streaming mops the floor with it.


Andrei
April 23, 2009
> Yes. The way it should be is not with sink, but with the standard output iterator method put().
> 
> void streamOut(T, R)(T object, R range)
> {
>     foreach(x; a) range.put(x);
>     range.put(b);
>     range.put(c);
> }

Eh. Is a sink callback too simple and easy to use or what?
April 23, 2009
On Thu, 23 Apr 2009 09:06:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

>> 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.
>
> Yes. The way it should be is not with sink, but with the standard output iterator method put().
>
> void streamOut(T, R)(T object, R range)
> {
>      foreach(x; a) range.put(x);
>      range.put(b);
>      range.put(c);
> }

What is the T object for?

This has to go into object.d and be part of the runtime, where std.range doesn't exist.  There is nothing stopping you from calling:

streamOut(&outputrange.put);

So I'd rather have a sink function.

And I wholeheartedly agree that we need this.  I've run into many situations where toString makes no sense.

-Steve
April 23, 2009
grauzone wrote:
>> Yes. The way it should be is not with sink, but with the standard output iterator method put().
>>
>> void streamOut(T, R)(T object, R range)
>> {
>>     foreach(x; a) range.put(x);
>>     range.put(b);
>>     range.put(c);
>> }
> 
> Eh. Is a sink callback too simple and easy to use or what?

?

Andrei
April 23, 2009
Steven Schveighoffer wrote:
> On Thu, 23 Apr 2009 09:06:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> 
>>> 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.
>>
>> Yes. The way it should be is not with sink, but with the standard output iterator method put().
>>
>> void streamOut(T, R)(T object, R range)
>> {
>>      foreach(x; a) range.put(x);
>>      range.put(b);
>>      range.put(c);
>> }
> 
> What is the T object for?

Red herring. If streamOut is a member, no need for T.

> This has to go into object.d and be part of the runtime, where std.range doesn't exist.  There is nothing stopping you from calling:
> 
> streamOut(&outputrange.put);
> 
> So I'd rather have a sink function.

It must be a sink _object_ so it can hold its own state. And it must support put() so it integrates with statically-bound output ranges.

interface OutRange
{
    void put(... a number of overloads ...);
}

> And I wholeheartedly agree that we need this.  I've run into many situations where toString makes no sense.

Same here...


Andrei
« First   ‹ Prev
1 2 3 4 5 6 7 8