www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - dmd 2.029 release

reply Walter Bright <newshound1 digitalmars.com> writes:
This is a major revision to Phobos, including Andrei's revolutionary new 
range support.

http://www.digitalmars.com/d/2.0/changelog.html
http://ftp.digitalmars.com/dmd.2.029.zip
Apr 20 2009
next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 20 Apr 2009 09:09:09 +0200, Walter Bright <newshound1 digitalmars.com>
wrote:

 This is a major revision to Phobos, including Andrei's revolutionary new  
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Butbutbut... I've just barely managed to install 2.028 yet. Great work! Can't wait to try out the new ranges. -- Simen
Apr 20 2009
prev sibling next sibling parent reply BCS <none anon.com> writes:
Hello Walter,

 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Cool template function literals sounds interesting
Apr 20 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
BCS Wrote:
 Cool template function literals sounds interesting
May I have one example of them? I am looking in the docs, but I am not finding anything... Bye, bearophile
Apr 20 2009
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 BCS Wrote:
 Cool template function literals sounds interesting
May I have one example of them? I am looking in the docs, but I am not finding anything...
void foo(alias f)() { f(3, 4); } foo!((x,y){return x * y;))();
Apr 20 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 void foo(alias f)()
 {
      f(3, 4);
 }
 foo!((x,y){return x * y;))();
I have tried: import std.stdio: writeln; void foo(alias f)() { f(3, 4); } void main() { foo!( (x, y) { writeln(x * y); } )(); } And it works, printing 12 :-) Very cute. This is able to simplify some of the code of (D1) dlibs :-) I didn't even know that lambda delegates in D2 can now infer the type of their input argument, so you can use (x, y) instead of (int x, int y). Can you tell me when this was changed? :-) Bye, bearophile
Apr 20 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
In D1 I have written a very hairy (but not too much long) apply() function,
that given a function and some arguments, returns the result of the function
applied to them. (apply() is a basic higher-order thing common in most
functional languages).

So now I'm playing with this new toy of D2, not using it in a serious way yet,
and I have written:

import std.stdio: writeln;
auto apply(alias f, TyArgs...)(TyArgs args) {
    return f(args);
}
void main() {
    writeln(  apply!( (x, y) { return x * y; } )(3, 4)  );
}

But when I compile it the compile spits out at compile-time:
Assertion failure: '0' on line 935 in file 'glue.c'

Bye,
bearophile
Apr 20 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
bearophile wrote:
 In D1 I have written a very hairy (but not too much long) apply() function,
that given a function and some arguments, returns the result of the function
applied to them. (apply() is a basic higher-order thing common in most
functional languages).
 
 So now I'm playing with this new toy of D2, not using it in a serious way yet,
and I have written:
 
 import std.stdio: writeln;
 auto apply(alias f, TyArgs...)(TyArgs args) {
     return f(args);
 }
 void main() {
     writeln(  apply!( (x, y) { return x * y; } )(3, 4)  );
 }
 
 But when I compile it the compile spits out at compile-time:
 Assertion failure: '0' on line 935 in file 'glue.c'
 
 Bye,
 bearophile
Your code should work as expected. (Also, right off the bat, any assertion failure in the compiler is a bug.) Could you submit to bugzilla? Andrei
Apr 20 2009
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Assertion failure: '0' on line 935 in file 'glue.c'
All assertion failures are compiler bugs and belong in bugzilla: http://d.puremagic.com/issues/show_bug.cgi?id=2863
Apr 20 2009
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 I didn't even know that lambda delegates in D2 can now infer the type
 of their input argument, so you can use (x, y) instead of (int x, int
 y). Can you tell me when this was changed? :-)
That change *is* the template function literals, and they are only valid as template arguments.
Apr 20 2009
prev sibling parent reply tama <repeatedly gmail.com> writes:
On Mon, 20 Apr 2009 18:12:16 +0900, Walter Bright  
<newshound1 digitalmars.com> wrote:

 bearophile wrote:
 BCS Wrote:
 Cool template function literals sounds interesting
May I have one example of them? I am looking in the docs, but I am not finding anything...
void foo(alias f)() { f(3, 4); } foo!((x,y){return x * y;))();
void foo(alias f)() { writefln(f(3, 4)); } foo!((x,y){ return x * y; })(); This code doesn't work(compile error). But, following code works. void bar(alias f)() { writefln(f("bar")); } bar!((str) { return str; })(); Is this a bug? -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/ $B%a%s%P!<Jg=8Cf(B http://tpf.techtalk.jp/
Apr 20 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
tama:
 void foo(alias f)()
 {
      writefln(f(3, 4));
 }
 foo!((x,y){ return x * y; })();
 
 This code doesn't work(compile error).
To me the following works: import std.stdio: writeln; void foo(alias f)() { writeln(f(3, 4)); } void main() { foo!((x,y){ return x * y; })(); } Bye, bearophile
Apr 20 2009
parent reply tama <repeatedly gmail.com> writes:
bearophile wrote:
 tama:
 void foo(alias f)()
 {
      writefln(f(3, 4));
 }
 foo!((x,y){ return x * y; })();

 This code doesn't work(compile error).
To me the following works: import std.stdio: writeln; void foo(alias f)() { writeln(f(3, 4)); } void main() { foo!((x,y){ return x * y; })(); }
I see. I tested following code. writefln(3 * 4); This code doesn't work in the first place:-< Sorry, it didn't matter. -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/ $B%a%s%P!<Jg=8Cf(B http://tpf.techtalk.jp/
Apr 20 2009
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 20 Apr 2009 14:58:38 +0400, tama <repeatedly gmail.com> wrote:

 bearophile wrote:
 tama:
 void foo(alias f)()
 {
      writefln(f(3, 4));
 }
 foo!((x,y){ return x * y; })();

 This code doesn't work(compile error).
To me the following works: import std.stdio: writeln; void foo(alias f)() { writeln(f(3, 4)); } void main() { foo!((x,y){ return x * y; })(); }
I see. I tested following code. writefln(3 * 4); This code doesn't work in the first place:-< Sorry, it didn't matter.
writefln now expects a string as a first argument. Use writeln() if you need no formattings, it is both faster and safer.
Apr 20 2009
parent tama <repeatedly gmail.com> writes:
Denis Koroskin wrote:
 writefln now expects a string as a first argument.
 Use writeln() if you need no formattings, it is both faster and safer.
To one's shame, I didn't know detailed writef/writefln spec. I checked D2 changelog and founded it at version 2.006 and 2.029. Thanks! -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/ $B%a%s%P!<Jg=8Cf(B http://tpf.techtalk.jp/
Apr 20 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
tama wrote:
 I tested following code.
 
 writefln(3 * 4);
 
 This code doesn't work in the first place:-<
Yes, that's one of the breaking changes in the new phobos2. writefln expects its first argument to be a format string. If it isn't, use writeln instead.
Apr 20 2009
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Walter Bright wrote:
 tama wrote:
 I tested following code.

 writefln(3 * 4);

 This code doesn't work in the first place:-<
Yes, that's one of the breaking changes in the new phobos2. writefln expects its first argument to be a format string. If it isn't, use writeln instead.
I just hit the same breakage. :( Since the compiler can detect this situation statically, shouldn't Phobos just statically redirect the call to writeln() ?
Apr 19 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Russell Lewis wrote:
 Walter Bright wrote:
 tama wrote:
 I tested following code.

 writefln(3 * 4);

 This code doesn't work in the first place:-<
Yes, that's one of the breaking changes in the new phobos2. writefln expects its first argument to be a format string. If it isn't, use writeln instead.
I just hit the same breakage. :( Since the compiler can detect this situation statically, shouldn't Phobos just statically redirect the call to writeln() ?
It did for a while. For cleanliness purposes, I thought it was about time to eliminate that. Also, extraneous arguments passed to writef will be ignored, not printed with default formatting. Andrei
Apr 20 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 extraneous arguments passed to writef will 
 be ignored, not printed with default formatting.
That sounds bad: => "Errors should never pass silently." It's better to raise a compilation error. (And if that's not possible, then an exception at run-time. But a compilation error is much better). Bye, bearophile
Apr 20 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
bearophile wrote:
 Andrei Alexandrescu:
 extraneous arguments passed to writef will be ignored, not printed
 with default formatting.
That sounds bad: => "Errors should never pass silently." It's better to raise a compilation error. (And if that's not possible, then an exception at run-time. But a compilation error is much better).
If it were an error, I wouldn't let it go. A good use case is string tables - a formatted message may or may not use all of the available information. Andrei
Apr 20 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles. Bye, bearophile
Apr 20 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to bearophile,

 Andrei Alexandrescu:
 
 If it were an error, I wouldn't let it go.
 
It's an error. It will lead to troubles. Bye, bearophile
Then there need to be a way for the format string to use an argument without generating output for it because as Andrei is saying, there are real world cases where not using all the args is *normal* and not an error. One option would be to not throw an error if the format string uses indexing formats (e.i. out of order formatting)
Apr 20 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
BCS wrote:
 Reply to bearophile,
 
 Andrei Alexandrescu:

 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles. Bye, bearophile
Then there need to be a way for the format string to use an argument without generating output for it because as Andrei is saying, there are real world cases where not using all the args is *normal* and not an error. One option would be to not throw an error if the format string uses indexing formats (e.i. out of order formatting)
Yah, that's an option I considered. Maybe it's the best way to go. Andrei
Apr 20 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gsiqdr$1csj$2 digitalmars.com...
 BCS wrote:
 Reply to bearophile,

 Andrei Alexandrescu:

 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles. Bye, bearophile
Then there need to be a way for the format string to use an argument without generating output for it because as Andrei is saying, there are real world cases where not using all the args is *normal* and not an error. One option would be to not throw an error if the format string uses indexing formats (e.i. out of order formatting)
Yah, that's an option I considered. Maybe it's the best way to go.
That would be far too clumbsy, unless you made it into two separate functions. For instance (psuedocode): auto userInput = getUserInput() // userInput now contains "{Name} at {Address}", zip deliberately ignored writefln(userInput, name, address, zip); // They're used in-order, but there shouldn't be an error
Apr 20 2009
parent reply BCS <ao pathlink.com> writes:
Reply to Nick,

 "Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message
 news:gsiqdr$1csj$2 digitalmars.com...
 
 BCS wrote:
 One option would be to not throw an error if the format string uses
 indexing formats (e.i. out of order formatting)
 
Yah, that's an option I considered. Maybe it's the best way to go.
That would be far too clumbsy, unless you made it into two separate functions. For instance (psuedocode): auto userInput = getUserInput() // userInput now contains "{Name} at {Address}", zip deliberately ignored writefln(userInput, name, address, zip); // They're used in-order, but there shouldn't be an error
They are in order but are listed by name so the error doesn't throw. The case where the error would be thrown is where the only format strings used are the "get the next arg" kind.
Apr 20 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <ao pathlink.com> wrote in message 
news:78ccfa2d3e68b8cb8fe69f8b7fba news.digitalmars.com...
 Reply to Nick,

 "Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message
 news:gsiqdr$1csj$2 digitalmars.com...

 BCS wrote:
 One option would be to not throw an error if the format string uses
 indexing formats (e.i. out of order formatting)
Yah, that's an option I considered. Maybe it's the best way to go.
That would be far too clumbsy, unless you made it into two separate functions. For instance (psuedocode): auto userInput = getUserInput() // userInput now contains "{Name} at {Address}", zip deliberately ignored writefln(userInput, name, address, zip); // They're used in-order, but there shouldn't be an error
They are in order but are listed by name so the error doesn't throw. The case where the error would be thrown is where the only format strings used are the "get the next arg" kind.
I was just using names for illustrative purposes. Also, I was under the impression that printf-style "get the next arg" formatting codes were the only ones writef supported. Is this not so?
Apr 20 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Nick Sabalausky wrote:
 "BCS" <ao pathlink.com> wrote in message 
 news:78ccfa2d3e68b8cb8fe69f8b7fba news.digitalmars.com...
 Reply to Nick,

 "Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message
 news:gsiqdr$1csj$2 digitalmars.com...

 BCS wrote:
 One option would be to not throw an error if the format string uses
 indexing formats (e.i. out of order formatting)
Yah, that's an option I considered. Maybe it's the best way to go.
That would be far too clumbsy, unless you made it into two separate functions. For instance (psuedocode): auto userInput = getUserInput() // userInput now contains "{Name} at {Address}", zip deliberately ignored writefln(userInput, name, address, zip); // They're used in-order, but there shouldn't be an error
They are in order but are listed by name so the error doesn't throw. The case where the error would be thrown is where the only format strings used are the "get the next arg" kind.
I was just using names for illustrative purposes. Also, I was under the impression that printf-style "get the next arg" formatting codes were the only ones writef supported. Is this not so?
Since a few versions ago writef supports positional arguments with Posix syntax. Andrei
Apr 20 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
Andrei Alexandrescu wrote:
 Nick Sabalausky wrote:
 "BCS" <ao pathlink.com> wrote
 Reply to Nick,

 "Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message
 news:gsiqdr$1csj$2 digitalmars.com...

 BCS wrote:
 One option would be to not throw an error if the format string uses
 indexing formats (e.i. out of order formatting)
Yah, that's an option I considered. Maybe it's the best way to go.
That would be far too clumbsy, unless you made it into two separate functions. For instance (psuedocode): auto userInput = getUserInput() // userInput now contains "{Name} at {Address}", zip deliberately ignored writefln(userInput, name, address, zip); // They're used in-order, but there shouldn't be an error
They are in order but are listed by name so the error doesn't throw. The case where the error would be thrown is where the only format strings used are the "get the next arg" kind.
I was just using names for illustrative purposes. Also, I was under the impression that printf-style "get the next arg" formatting codes were the only ones writef supported. Is this not so?
Since a few versions ago writef supports positional arguments with Posix syntax. Andrei
Positional format specifications really make a huge difference, especially where one needs to have the user interface in several languages. Thanks for them!! Now, for the case without positional format specifications, we could (and I guess, should) have a solution to "the wrong number of arguments" problem. If we have: - a non-printing format spec - a munch-the-remaining-ones format spec - an ignore-too-few-arguments format spec we could cover all the needed cases. The first one lets you use one parameter without printing it. (Maybe you don't want to print the middle part of somebody's name.) The second is used when you don't want to print possibly many remaining arguments, say the address of someone, or the country. The last one, is for the case where you use a single format string in several contexts, some of which you suspect may not contain enough information to be formally correct, but where you are satisfied to print an empty string '' (that is, not print anything) for them. This situation might arise when the format string originates from outside the program. ** When none of the latter two are used, and there is the wrong number of arguments, I think a runtime exception should be thrown. The only time where I think a compile time error is warranted, is when the format string is a string literal, with the wrong number of arguments. The programmer may put the ignore-too-few-arguments format spec anywhere in the format string. Its effect starts from that point on.
Apr 20 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
bearophile wrote:
 Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles.
Well at most you could say it's error-prone, something that is easier to argue. The problem is that forcing it into an error makes quite a number of valid uses impossible. An example is a logging application that provides you a number of pieces of information (date, time, message, etc.) and you get to specify how they should be formatted. Oftentimes you'd choose to ignore some data. Andrei
Apr 20 2009
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Andrei Alexandrescu wrote:
 bearophile wrote:
 Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles.
Well at most you could say it's error-prone, something that is easier to argue. The problem is that forcing it into an error makes quite a number of valid uses impossible. An example is a logging application that provides you a number of pieces of information (date, time, message, etc.) and you get to specify how they should be formatted. Oftentimes you'd choose to ignore some data. Andrei
Fair enough. But then let's split off a version of the function which allows unused arguments. For most users, in most cases, unused arguments are indicative of an error. Case in point: I have been bitten by this perhaps half a dozen times *already* porting older code. This code used to work fine: writefln("The value is: %d", myVar, ". Do something!"); Now, it interprets the trailing string as an unused argument, and ignores it (silently). Ugh. Ofc, looking back, I don't like that old coding style...I'm migrating back more to C-style (give the whole format string first). But the fact that I had a *silent* error was frustrating. Russ
Apr 20 2009
parent Lutger <lutger.blijdestijn gmail.com> writes:
Russell Lewis wrote:

...
 Case in point: I have been bitten by this perhaps half a dozen times 
 *already* porting older code.  This code used to work fine:
 
 	writefln("The value is: %d", myVar, ".  Do something!");
 
... I bet a lot of to-be-ported D code will have this bug, I know my code will. When you want to print a format string this way - last argument(s) simply appended, it saves you two characters typing. When something saves any characters typing and produces the same result, programmers will do that.
Apr 21 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:gsipn1$1bng$1 digitalmars.com...
 Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles.
Sometimes it is an error, but there are times when it isn't: Suppose you're writing a reporting module for an employee database: --------------------- ID: 3234 Last: Doe First: John Phone: 555-5555 Zip: 90210 ID: 7642 Last: Smith Etc... --------------------- And you want the admins to be able to define their own reports: --------------------- Privileged Report: Unprivileged Report: For Each Person: "Name: {Last}, {First}\nContact Info Classified" Call List In Psuedo-Japanese: For Each Person Where Name="Smith": "SmithSan {LoopIndex}'s DenwaBango: {Phone}" --------------------- So then the report creation code: --------------------- foreach(int i, Person p; people.subset(customReport.whereClause)) writefln(customReport.formatStr, i, p.id, p.first, p.last, p.phone, p.zip); --------------------- That would be very difficult/limiting if every arg had to be used in the format string. string formatting superior to C/Phobos-style)
Apr 20 2009
next sibling parent reply renoX <renosky free.fr> writes:
Nick Sabalausky a écrit :
 "bearophile" <bearophileHUGS lycos.com> wrote in message 
 news:gsipn1$1bng$1 digitalmars.com...
 Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles.
Sometimes it is an error, but there are times when it isn't:
[cut]
 Call List In Psuedo-Japanese:
 For Each Person Where Name="Smith": "SmithSan {LoopIndex}'s DenwaBango: 
 {Phone}"
 ---------------------
 
 So then the report creation code:
 
 ---------------------
 foreach(int i, Person p; people.subset(customReport.whereClause))
     writefln(customReport.formatStr, i, p.id, p.first, p.last, p.phone, 
 p.zip);
 ---------------------
 
 That would be very difficult/limiting if every arg had to be used in the 
 format string.
Mmmh, is {LoopIndex} correct? It should be {i} I think and I would argue that this format string should generate an error (something better than a runtime exception would be nice but I'm not sure that this is possible). That said I agree that both are needed, so why not have either two different function or a function parameter which change the behaviour of the format string interpretation? By default writefln would complain if there is a possibility of an unused parameter, but you could do writefln(customReport.formatStr, i, p.id, p.first, p.last, p.phone, p.zip, allowUnused=true);

 string formatting superior to C/Phobos-style) 
I think that named format string are much superior to positional format string as they are easier to read/write.. BR, renoX
Apr 27 2009
parent "Nick Sabalausky" <a a.a> writes:
"renoX" <renosky free.fr> wrote in message news:49F56A74.4000606 free.fr...
 Nick Sabalausky a écrit :
 "bearophile" <bearophileHUGS lycos.com> wrote in message 
 news:gsipn1$1bng$1 digitalmars.com...
 Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles.
Sometimes it is an error, but there are times when it isn't:
[cut]
 Call List In Psuedo-Japanese:
 For Each Person Where Name="Smith": "SmithSan {LoopIndex}'s DenwaBango: 
 {Phone}"
 ---------------------

 So then the report creation code:

 ---------------------
 foreach(int i, Person p; people.subset(customReport.whereClause))
     writefln(customReport.formatStr, i, p.id, p.first, p.last, p.phone, 
 p.zip);
 ---------------------

 That would be very difficult/limiting if every arg had to be used in the 
 format string.
Mmmh, is {LoopIndex} correct? It should be {i} I think and I would argue that this format string should generate an error (something better than a runtime exception would be nice but I'm not sure that this is possible).
That was just for illustrative purposes.
 (Incidentally, this example also demonstrates why I consider 

I think that named format string are much superior to positional format string as they are easier to read/write..
Actually, I was referring to the ability to specify them out-of-order, repeat them, etc. (I didn't realize that Phobos's writef had recently gained support named strings, only numerical ones. I was just using names for illustrative purposes, and (unclearly) implying that the app would translate those named formats into numerical ones before passing them along to the string output function.
Apr 27 2009
prev sibling parent renoX <renosky free.fr> writes:
Nick Sabalausky a écrit :
 "bearophile" <bearophileHUGS lycos.com> wrote in message 
 news:gsipn1$1bng$1 digitalmars.com...
 Andrei Alexandrescu:
 If it were an error, I wouldn't let it go.
It's an error. It will lead to troubles.
Sometimes it is an error, but there are times when it isn't:
[cut]
 Call List In Psuedo-Japanese:
 For Each Person Where Name="Smith": "SmithSan {LoopIndex}'s DenwaBango: 
 {Phone}"
 ---------------------
 
 So then the report creation code:
 
 ---------------------
 foreach(int i, Person p; people.subset(customReport.whereClause))
     writefln(customReport.formatStr, i, p.id, p.first, p.last, p.phone, 
 p.zip);
 ---------------------
 
 That would be very difficult/limiting if every arg had to be used in the 
 format string.
Mmmh, is {LoopIndex} correct? It should be {i} I think and I would argue that this format string should generate an error (something better than a runtime exception would be nice but I'm not sure that this is possible). That said I agree that both are needed, so why not have either two different function or a function parameter which change the behaviour of the format string interpretation? By default writefln would complain if there is a possibility of an unused parameter, but you could do writefln(customReport.formatStr, i, p.id, p.first, p.last, p.phone, p.zip, allowUnused=true);

 string formatting superior to C/Phobos-style) 
I think that named format string are much superior to positional format string as they are easier to read/write.. BR, renoX
Apr 27 2009
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
bearophile wrote:
 BCS Wrote:
 Cool template function literals sounds interesting
May I have one example of them? I am looking in the docs, but I am not finding anything... Bye, bearophile
If I had to guess, I'd say it was something like this:
 alias (T)(T a, T b) { return (a+b)/2.0; } average;
Haven't had a chance to TRY that yet, mind you. :P -- Daniel
Apr 20 2009
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Daniel Keep wrote:
 
 bearophile wrote:
 BCS Wrote:
 Cool template function literals sounds interesting
May I have one example of them? I am looking in the docs, but I am not finding anything... Bye, bearophile
If I had to guess, I'd say it was something like this:
 alias (T)(T a, T b) { return (a+b)/2.0; } average;
Haven't had a chance to TRY that yet, mind you. :P -- Daniel
(Sees Walter's post) Guess not. :P -- Daniel
Apr 20 2009
prev sibling next sibling parent Georg Wrede <georg.wrede iki.fi> writes:
Walter Bright wrote:
 
 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Ooohhh, just half way through the change log, and already breathless!!!
Apr 20 2009
prev sibling next sibling parent reply "Saaa" <empty needmail.com> writes:
Using D1 feels especially retarded today :(

 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip 
Apr 20 2009
next sibling parent Georg Wrede <georg.wrede iki.fi> writes:
Saaa wrote:
 Using D1 feels especially retarded today :(
Don't cry now. :-) Soon you'll be using D2 for work, and cry when you see the D3 change log...
Apr 20 2009
prev sibling parent Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Mon, Apr 20, 2009 at 2:47 PM, Saaa <empty needmail.com> wrote:
 Using D1 feels especially retarded today :(
Why retarded ?
Apr 20 2009
prev sibling next sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Walter Bright wrote:
 
 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
The documentation for completeSort in std.algorithm says: Performs O(n * log(n)) (best case) to O(n * log(n)) (worst-case) evaluations of swap. I wonder what it should be.
Apr 20 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Georg Wrede wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
The documentation for completeSort in std.algorithm says: Performs O(n * log(n)) (best case) to O(n * log(n)) (worst-case) evaluations of swap. I wonder what it should be.
Sorry, what was I thinking? I think (without being sure) that the complexity of completeSort is O(rhs.length * log(t)) in the best case, and O(t * log(t)) in the worst case, where t = lhs.length + rhs.length. Andrei
Apr 20 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Andrei Alexandrescu wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
The documentation for completeSort in std.algorithm says: Performs O(n * log(n)) (best case) to O(n * log(n)) (worst-case) evaluations of swap. I wonder what it should be.
Sorry, what was I thinking? I think (without being sure) that the complexity of completeSort is O(rhs.length * log(t)) in the best case, and O(t * log(t)) in the worst case, where t = lhs.length + rhs.length.
I revise that. Best case, there's temporary memory to allocate and then the complexity is that of sorting rhs plus merge lhs and rhs using extra memory. That is O(lhs.length + rhs.length * log(rhs.length)). Worst case, there's no temporary memory available so we need to sort the whole thing. That means O((lhs.length + rhs.length) * log(rhs.length + rhs.length)). I committed the fixed module. Andrei
Apr 20 2009
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 This is a major revision to Phobos, including Andrei's revolutionary new
 range support.
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Two small issues I've just run into that might warrant a quick update: Line 908 in random.d calls the deprecated rand_seed() for the old school random number generators from the static constructor. This means that std.random just plain can't be used out of the box. Also, when using std.string, I get the following linker errors on the Win32 build: Symbol Undefined _D3std6string6striprFAyaZAya Symbol Undefined _D3std6string6striplFAyaZAya
Apr 20 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from dsimcha (dsimcha yahoo.com)'s article
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 This is a major revision to Phobos, including Andrei's revolutionary new
 range support.
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Two small issues I've just run into that might warrant a quick update: Line 908 in random.d calls the deprecated rand_seed() for the old school random number generators from the static constructor. This means that std.random just plain can't be used out of the box. Also, when using std.string, I get the following linker errors on the Win32 build: Symbol Undefined _D3std6string6striprFAyaZAya Symbol Undefined _D3std6string6striplFAyaZAya
Never mind on the linker error. That was caused by me forgetting to recompile parts of my code. The random thing looks legit, though.
Apr 20 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
dsimcha wrote:
 == Quote from dsimcha (dsimcha yahoo.com)'s article
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 This is a major revision to Phobos, including Andrei's revolutionary new
 range support.
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Two small issues I've just run into that might warrant a quick update: Line 908 in random.d calls the deprecated rand_seed() for the old school random number generators from the static constructor. This means that std.random just plain can't be used out of the box. Also, when using std.string, I get the following linker errors on the Win32 build: Symbol Undefined _D3std6string6striprFAyaZAya Symbol Undefined _D3std6string6striplFAyaZAya
Never mind on the linker error. That was caused by me forgetting to recompile parts of my code. The random thing looks legit, though.
Ok, I've undeprecated rand_seed, sigh. I was hoping I'd eliminate rand() entirely from this release, but Walter pointed out it would break too much code. So I left rand() and rand_seed() as deprecated. Now I only left rand() deprecated so at least the static constructor works. Andrei
Apr 20 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 Ok, I've undeprecated rand_seed, sigh. I was hoping I'd eliminate rand() 
 entirely from this release, but Walter pointed out it would break too 
 much code. So I left rand() and rand_seed() as deprecated. Now I only 
 left rand() deprecated so at least the static constructor works.
I think the right fix for that is for the compiler to not complain about deprecated symbol usage if the usage is in the same module the deprecated symbol is defined in.
Apr 20 2009
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2864
Apr 20 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 Andrei Alexandrescu wrote:
 Ok, I've undeprecated rand_seed, sigh. I was hoping I'd eliminate 
 rand() entirely from this release, but Walter pointed out it would 
 break too much code. So I left rand() and rand_seed() as deprecated. 
 Now I only left rand() deprecated so at least the static constructor 
 works.
I think the right fix for that is for the compiler to not complain about deprecated symbol usage if the usage is in the same module the deprecated symbol is defined in.
Reading this, I thought "No chance Walter will ever do this" until I saw the poster's name :o). Andrei
Apr 20 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 Walter Bright wrote:
 I think the right fix for that is for the compiler to not complain 
 about deprecated symbol usage if the usage is in the same module the 
 deprecated symbol is defined in.
Reading this, I thought "No chance Walter will ever do this" until I saw the poster's name :o).
It is consistent with the ideas behind private access. Presumably the person working on the module knows what they're doing, no need to hide it from himself.
Apr 20 2009
prev sibling next sibling parent reply "Craig Black" <craigblack2 cox.net> writes:
I like very much the direction D2 is going now.  Language refactoring and 
enhancements driven by the goal of more elegant implementation of standard 
libraries.  This approach seems very practical and promising.  Thank you 
very much and keep it up!

-Craig 
Apr 20 2009
next sibling parent reply superdan <super dan.org> writes:
Craig Black Wrote:

 I like very much the direction D2 is going now.  Language refactoring and 
 enhancements driven by the goal of more elegant implementation of standard 
 libraries.  This approach seems very practical and promising.  Thank you 
 very much and keep it up!
 
 -Craig 
holy guacashit this works. import std.algorithm; import std.range; import std.stdio; void main() { string[] a = [ "shit", "poop" ]; string[] b = [ "dump", "shite" ]; sort!((a, b) { return a > b; })(chain(a, b)); writeln(a, " ", b); } i'll be shat on. couple shitty problems tho. auto don't work shit for a and b. complains about fixed size strings'n'shit. then writeln(chain(a, b)) shites ChainImpl!(immutable(char)[][],immutable(char)[][]) to stdout. tat's liable to scare da shit outta a beginner.
Apr 20 2009
next sibling parent downs <default_357-line yahoo.de> writes:
superdan wrote:
 Craig Black Wrote:
 
 I like very much the direction D2 is going now.  Language refactoring and 
 enhancements driven by the goal of more elegant implementation of standard 
 libraries.  This approach seems very practical and promising.  Thank you 
 very much and keep it up!

 -Craig 
holy guacashit this works. import std.algorithm; import std.range; import std.stdio; void main() { string[] a = [ "shit", "poop" ]; string[] b = [ "dump", "shite" ]; sort!((a, b) { return a > b; })(chain(a, b)); writeln(a, " ", b); } i'll be shat on. couple shitty problems tho. auto don't work shit for a and b. complains about fixed size strings'n'shit. then writeln(chain(a, b)) shites ChainImpl!(immutable(char)[][],immutable(char)[][]) to stdout. tat's liable to scare da shit outta a beginner.
Poop is funny! :)
Apr 20 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
superdan wrote:
 Craig Black Wrote:
 
 I like very much the direction D2 is going now.  Language refactoring and 
 enhancements driven by the goal of more elegant implementation of standard 
 libraries.  This approach seems very practical and promising.  Thank you 
 very much and keep it up!

 -Craig 
holy guacashit this works. import std.algorithm; import std.range; import std.stdio; void main() { string[] a = [ "shit", "poop" ]; string[] b = [ "dump", "shite" ]; sort!((a, b) { return a > b; })(chain(a, b)); writeln(a, " ", b); } i'll be shat on. couple shitty problems tho. auto don't work shit for a and b. complains about fixed size strings'n'shit. then writeln(chain(a, b)) shites ChainImpl!(immutable(char)[][],immutable(char)[][]) to stdout. tat's liable to scare da shit outta a beginner.
Thanks... I guess :o). Any chance you could submit the issues to bugzilla? I think the problem with string arrays is already known, but I need a memento to make writeln work with ranges. Andrei
Apr 20 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Craig Black wrote:
 I like very much the direction D2 is going now.  Language refactoring 
 and enhancements driven by the goal of more elegant implementation of 
 standard libraries.  This approach seems very practical and promising.  
 Thank you very much and keep it up!
 
 -Craig
Thanks. Walter pointed out to me something interesting - STL is non-intuitive. That doesn't make it any less true (as a pursuit of the most generic incarnation of fundamental structs and algos). It's non-intuitive the same way complex numbers and relativity theory are non-intuitive. No language has ever managed to comprehend STL by sheer chance. (This in There are two that can express it at all: C++ and D. Both C++ and D had to be changed to allow STL to exist, and became better languages as a result. The range shtick and D's support for lambdas is taking STL support to a whole new level. The downside is, it's rather difficult to explain the STL to anyone using other languages and wanting to just figure what the STL buzz is all about. Andrei
Apr 20 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Andrei Alexandrescu wrote:
 Craig Black wrote:
 I like very much the direction D2 is going now.  Language refactoring 
 and enhancements driven by the goal of more elegant implementation of 
 standard libraries.  This approach seems very practical and 
 promising.  Thank you very much and keep it up!

 -Craig
Thanks. Walter pointed out to me something interesting - STL is non-intuitive. That doesn't make it any less true (as a pursuit of the most generic incarnation of fundamental structs and algos). It's non-intuitive the same way complex numbers and relativity theory are non-intuitive. No language has ever managed to comprehend STL by sheer chance. (This in There are two that can express it at all: C++ and D. Both C++ and D had to be changed to allow STL to exist, and became better languages as a result. The range shtick and D's support for lambdas is taking STL support to a whole new level. The downside is, it's rather difficult to explain the STL to anyone using other languages and wanting to just figure what the STL buzz is all about.
I wrote my MSc thesis about the STL. I think the conceptual idea was clean and clear, and at the time it was reasonably easy to explain it to even the professors. ;-) Today, however, and especially with the advanced implementation we have here in D, if someone has no prior knowledge of the STL way of thinking, it may be really hard to get them to 'get it'. There are too many trees up front to grasp the forest. What's sad, http://en.wikipedia.org/wiki/Standard_Template_Library really sucks at introducing the STL on a conceptual level. Even worse, that is actually the only thing it *should* do. Everyting else is optional.
Apr 20 2009
parent Leandro Lucarella <llucax gmail.com> writes:
Georg Wrede, el 21 de abril a las 09:25 me escribiste:
 What's sad, http://en.wikipedia.org/wiki/Standard_Template_Library
 really sucks at introducing the STL on a conceptual level. Even worse, that is 
 actually the only thing it *should* do. Everyting else is optional.
You should improve it then =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ----------------------------------------------------------------------------
Apr 21 2009
prev sibling next sibling parent Georg Wrede <georg.wrede iki.fi> writes:
Walter Bright wrote:

In std.array, the example for back() is the same as for front().


The example for put() seems to be correct (and put() behaves 
accordingly), however, the asserted results are not what the reader 
would expect.

If we are verbose enough to explain the dot notation here, then it would 
be prudent to elaborate a little as to the point of put(), and possibly 
the example (or the explanation) could include a use case.
Apr 20 2009
prev sibling next sibling parent reply Russell Lewis <webmaster villagersonline.com> writes:
Walter Bright wrote:
 
 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Was fwritefln() removed intentionally? Or should I write up a Bugzilla? I didn't noteice a mention in changelog.
Apr 19 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Russell Lewis wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Was fwritefln() removed intentionally? Or should I write up a Bugzilla? I didn't noteice a mention in changelog.
Sorry. It was removed intentionally along with all functions that manipulate FILE* directly. Its functional equivalent is File.writefln. If all you have is a handle, use File.wrapFile(fhandle).writefln. Andrei
Apr 20 2009
prev sibling next sibling parent reply annoyed <abc email.com> writes:
It's in dmd-v2.026/src/phobos/std/stdio.d:void fwritefln(FILE* fp, ...)

but I cannot find it in 2.029.
Apr 20 2009
parent Tyro[a.c.edwards] <nospam home.com> writes:
annoyed Wrote:

 It's in dmd-v2.026/src/phobos/std/stdio.d:void fwritefln(FILE* fp, ...)
 
 but I cannot find it in 2.029.
 
It was removed, use File.writefln() instead. std.stdio has been rewritten so you might want to take a look at the docs. Andrew
Apr 20 2009
prev sibling next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Walter, how often do you update your working copy from the SVN? 
Obviously less than once every 2 releases.

Stewart.
Apr 20 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Stewart Gordon wrote:
 Walter, how often do you update your working copy from the SVN? 
 Obviously less than once every 2 releases.
As far as I know, it is current. Everything got checked in.
Apr 20 2009
next sibling parent reply BCS <none anon.com> writes:
Hello Walter,

 Stewart Gordon wrote:
 
 Walter, how often do you update your working copy from the SVN?
 Obviously less than once every 2 releases.
 
As far as I know, it is current. Everything got checked in.
I think he was asking about the otherway (not that I known why)
Apr 20 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
BCS wrote:
 I think he was asking about the otherway (not that I known why)
I think he'll need to be more specific!
Apr 20 2009
parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
Well, there's push (svn commit) and pull (svn up), so he must mean one 
or the other...

-[Unknown]


Walter Bright wrote:
 BCS wrote:
 I think he was asking about the otherway (not that I known why)
I think he'll need to be more specific!
Apr 20 2009
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Walter Bright wrote:
 Stewart Gordon wrote:
 Walter, how often do you update your working copy from the SVN? 
 Obviously less than once every 2 releases.
As far as I know, it is current. Everything got checked in.
So how has the fix for http://d.puremagic.com/issues/show_bug.cgi?id=2580 (and probably others) not been included? Stewart.
Apr 21 2009
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Stewart Gordon wrote:
 So how has the fix for
 http://d.puremagic.com/issues/show_bug.cgi?id=2580
 (and probably others) not been included?
I'll look into it.
Apr 27 2009
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
Stewart Gordon wrote:
 Walter Bright wrote:
 Stewart Gordon wrote:
 Walter, how often do you update your working copy from the SVN? 
 Obviously less than once every 2 releases.
As far as I know, it is current. Everything got checked in.
So how has the fix for http://d.puremagic.com/issues/show_bug.cgi?id=2580 (and probably others) not been included?
The code fix for this is in. You can see it in dmd/src/compiler/dmd/dmain2.d: rt_init(). I haven't updated the documentation yet though (this last release took me a bit by surprise)--I'll take care of that before the next release.
Apr 27 2009
prev sibling next sibling parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Mon, 20 Apr 2009 00:09:09 -0700, Walter Bright
<newshound1 digitalmars.com> wrote:

This is a major revision to Phobos, including Andrei's revolutionary new 
range support.

http://www.digitalmars.com/d/2.0/changelog.html
http://ftp.digitalmars.com/dmd.2.029.zip
Wicked awesome! file:///C:/dmd/html/d/phobos/std_range.html#cons Looks like bug 2676 was fixed in 2.027
Apr 20 2009
parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Mon, 20 Apr 2009 09:57:55 +0200, Max Samukha
<samukha voliacable.com.removethis> wrote:

On Mon, 20 Apr 2009 00:09:09 -0700, Walter Bright
<newshound1 digitalmars.com> wrote:

This is a major revision to Phobos, including Andrei's revolutionary new 
range support.

http://www.digitalmars.com/d/2.0/changelog.html
http://ftp.digitalmars.com/dmd.2.029.zip
Wicked awesome! file:///C:/dmd/html/d/phobos/std_range.html#cons
http://www.digitalmars.com/d/2.0/phobos/std_range.html#cons
Looks like bug 2676 was fixed in 2.027
Apr 21 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Max Samukha wrote:
 On Mon, 20 Apr 2009 09:57:55 +0200, Max Samukha
 <samukha voliacable.com.removethis> wrote:
 
 On Mon, 20 Apr 2009 00:09:09 -0700, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Wicked awesome! file:///C:/dmd/html/d/phobos/std_range.html#cons
http://www.digitalmars.com/d/2.0/phobos/std_range.html#cons
 Looks like bug 2676 was fixed in 2.027
Thanks. I uncommented the unittest, updated the doc, and checked in. Andrei
Apr 21 2009
parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Tue, 21 Apr 2009 07:42:46 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

Max Samukha wrote:
 On Mon, 20 Apr 2009 09:57:55 +0200, Max Samukha
 <samukha voliacable.com.removethis> wrote:
 
 On Mon, 20 Apr 2009 00:09:09 -0700, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Wicked awesome! file:///C:/dmd/html/d/phobos/std_range.html#cons
http://www.digitalmars.com/d/2.0/phobos/std_range.html#cons
 Looks like bug 2676 was fixed in 2.027
Thanks. I uncommented the unittest, updated the doc, and checked in. Andrei
A couple more minor doc issues: http://www.digitalmars.com/d/2.0/phobos/std_range.html: instances of "the popFront" need to be corrected to "the next". On the std.algorithm page, the examples for "map" and "filter" don't compile due to the fixed size array in equal(). The example for "bringToFront" is outdated. The comments for "remove": "If $(s =" -> "If $(D s ="
Apr 22 2009
parent reply Brad Roberts <braddr puremagic.com> writes:
Max Samukha wrote:
 On Tue, 21 Apr 2009 07:42:46 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Max Samukha wrote:
 On Mon, 20 Apr 2009 09:57:55 +0200, Max Samukha
 <samukha voliacable.com.removethis> wrote:

 On Mon, 20 Apr 2009 00:09:09 -0700, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Wicked awesome! file:///C:/dmd/html/d/phobos/std_range.html#cons
http://www.digitalmars.com/d/2.0/phobos/std_range.html#cons
 Looks like bug 2676 was fixed in 2.027
Thanks. I uncommented the unittest, updated the doc, and checked in. Andrei
A couple more minor doc issues: http://www.digitalmars.com/d/2.0/phobos/std_range.html: instances of "the popFront" need to be corrected to "the next". On the std.algorithm page, the examples for "map" and "filter" don't compile due to the fixed size array in equal(). The example for "bringToFront" is outdated. The comments for "remove": "If $(s =" -> "If $(D s ="
Please file a bug report. Posts here are are good way for issues to fall through the cracks. Thanks, Brad
Apr 22 2009
parent Max Samukha <samukha voliacable.com.removethis> writes:
On Wed, 22 Apr 2009 00:32:27 -0700, Brad Roberts
<braddr puremagic.com> wrote:

Max Samukha wrote:
 On Tue, 21 Apr 2009 07:42:46 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Max Samukha wrote:
 On Mon, 20 Apr 2009 09:57:55 +0200, Max Samukha
 <samukha voliacable.com.removethis> wrote:

 On Mon, 20 Apr 2009 00:09:09 -0700, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Wicked awesome! file:///C:/dmd/html/d/phobos/std_range.html#cons
http://www.digitalmars.com/d/2.0/phobos/std_range.html#cons
 Looks like bug 2676 was fixed in 2.027
Thanks. I uncommented the unittest, updated the doc, and checked in. Andrei
A couple more minor doc issues: http://www.digitalmars.com/d/2.0/phobos/std_range.html: instances of "the popFront" need to be corrected to "the next". On the std.algorithm page, the examples for "map" and "filter" don't compile due to the fixed size array in equal(). The example for "bringToFront" is outdated. The comments for "remove": "If $(s =" -> "If $(D s ="
Please file a bug report. Posts here are are good way for issues to fall through the cracks. Thanks, Brad
done http://d.puremagic.com/issues/show_bug.cgi?id=2874
Apr 22 2009
prev sibling next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Walter Bright wrote:
 
 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work? I admit I don't know much about these things, and what I'm going to say next may not make sense at all, but here goes: x86-64 is just a superset of x86, right? Wouldn't it be possible, as a first step in the direction of a full-fledged x86-64 compiler, to simply make one that uses the same instruction set as the current DMD, but, I dunno, marks the executable as 64-bit (or something like that)? Specialisation and optimisation for the 64-bit architecture could then come at a later point in time. I know it is possible to run the 32-bit compiler (and the executables it produces) on a 64-bit operating system, but it isn't possible to link against 64-bit libraries. This means that one has to install and maintain 32-bit versions of all the libraries one wants to use, and those are, in general, not available through the repositories of most 64-bit distros. -Lars
Apr 21 2009
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Lars T. Kyllingstad wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work? I admit I don't know much about these things, and what I'm going to say next may not make sense at all, but here goes: x86-64 is just a superset of x86, right? Wouldn't it be possible, as a first step in the direction of a full-fledged x86-64 compiler, to simply make one that uses the same instruction set as the current DMD, but, I dunno, marks the executable as 64-bit (or something like that)? Specialisation and optimisation for the 64-bit architecture could then come at a later point in time.
It's not quite that simple. It's not a full superset; some x86 instructions are not valid x86-64 instructions. For example, I think 'inc' was removed to make place for prefixes that set some flags for the next instruction and allow it to use the extra registers r8-r15.
Apr 21 2009
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Lars T. Kyllingstad wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work? I admit I don't know much about these things, and what I'm going to say next may not make sense at all, but here goes: x86-64 is just a superset of x86, right? Wouldn't it be possible, as a first step in the direction of a full-fledged x86-64 compiler, to simply make one that uses the same instruction set as the current DMD, but, I dunno, marks the executable as 64-bit (or something like that)? Specialisation and optimisation for the 64-bit architecture could then come at a later point in time.
I'm pretty sure that 64-bit code is binary incompatible with 32-bit code. For example: struct Foo { void* ptr; } Is a different size for 32-bit and 64-bit code.
 I know it is possible to run the 32-bit compiler (and the executables it
 produces) on a 64-bit operating system, but it isn't possible to link
 against 64-bit libraries. This means that one has to install and
 maintain 32-bit versions of all the libraries one wants to use, and
 those are, in general, not available through the repositories of most
 64-bit distros.
This is because the OS puts the CPU into a 32-bit compatible mode, but it can't magic away the differences between 32-bit and 64-bit code.
 -Lars
The best bet for 64-bit D executables at this point is probably LDC; dunno what the current state is, though. -- Daniel
Apr 21 2009
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Daniel Keep wrote:
 
 Lars T. Kyllingstad wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but...
[snip]
 
 The best bet for 64-bit D executables at this point is probably LDC;
 dunno what the current state is, though.
The state for D2 is currently "very broken", AFAIK.
Apr 21 2009
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Daniel Keep wrote:

...
 -Lars
The best bet for 64-bit D executables at this point is probably LDC; dunno what the current state is, though. -- Daniel
if you grep the dmd backend sources for x86_64, you'll get some results. Don't know what that means though, the source looks like magic to me!
Apr 21 2009
parent reply Don <nospam nospam.com> writes:
Lutger wrote:
 Daniel Keep wrote:
 
 ...
 -Lars
The best bet for 64-bit D executables at this point is probably LDC; dunno what the current state is, though. -- Daniel
if you grep the dmd backend sources for x86_64, you'll get some results. Don't know what that means though, the source looks like magic to me!
They're just part of the standard OBJ file format. Nothing to do with code generation. Much more fun is: $ cd src/dmd $ grep "goto " * -R
Apr 21 2009
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Don wrote:

 Lutger wrote:
 Daniel Keep wrote:
 
 ...
 -Lars
The best bet for 64-bit D executables at this point is probably LDC; dunno what the current state is, though. -- Daniel
if you grep the dmd backend sources for x86_64, you'll get some results. Don't know what that means though, the source looks like magic to me!
They're just part of the standard OBJ file format. Nothing to do with code generation. Much more fun is: $ cd src/dmd $ grep "goto " * -R
you forgot " | less" there, what the hell...this code can't be human.
Apr 21 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Apr 21 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
Apr 21 2009
next sibling parent reply Don <nospam nospam.com> writes:
Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
It'd be really funny to pass it through one of those "code quality" metrics, one of the ones with a ridiculously heavy penalty for using goto. I think it'd tell you that DMD source is almost the lowest-quality code on the planet. <g> Actually, looking through the DMD source it becomes obvious that goto is really not a problem at all. The lack of comments is much more of a problem. (Especially with files with names like "e2ir.c". What the heck is "fltables.c", "cdxxx.c", "elxxx.c" ?). Even so, it's mostly not that difficult to understand.
Apr 22 2009
next sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Don wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
It'd be really funny to pass it through one of those "code quality" metrics, one of the ones with a ridiculously heavy penalty for using goto. I think it'd tell you that DMD source is almost the lowest-quality code on the planet. <g>
Yeah. But now I'm getting a bad conscience, this is beginning to look like Walter-bashing... :-)
 Actually, looking through the DMD source it becomes obvious that goto is 
 really not a problem at all. The lack of comments is much more of a 
 problem. (Especially with files with names like "e2ir.c". What the heck 
 is "fltables.c", "cdxxx.c", "elxxx.c" ?). Even so, it's mostly not that 
 difficult to understand.
I guess Walter has to keep alternating between ASM, C and D. And a lot of ASM coding is nothing more than a bunch of MOV and JMP stuff. And file naming conventions here look like what one typically finds in development code (before some pre-publishing guy has tidyed it up with a lot of global search&replaces). And, after all, the C files never were meant to be public anyway. Actually, the one interesting question might be, would rewriting this code in a structured fashion (I mean, removing the gotos) make it slower? (Not that I'd be suggesting Walter should do it. Just an academic question.)
Apr 22 2009
next sibling parent reply Don <nospam nospam.com> writes:
Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
It'd be really funny to pass it through one of those "code quality" metrics, one of the ones with a ridiculously heavy penalty for using goto. I think it'd tell you that DMD source is almost the lowest-quality code on the planet. <g>
Yeah. But now I'm getting a bad conscience, this is beginning to look like Walter-bashing... :-)
I think those code quality metrics are ridiculous. The prejudice against 'goto' is really just brainwashing and totally without basis. Here's a recent link from Andrew Koenig, who really should know better. http://dobbscodetalk.com/index.php?option=com_myblog&show=What-Dijkstra-said-was-harmful-about-goto-statements.html&Itemid=29 Can you see his fundamental mistake? He talks about "the program" (just as Dijkstra said), but it's just not relevant for C/C++/D/Pascal/... or any other structured programming language. Wherever he says "program" you should substitute "function". And then the force of the argument totally disappears. The problem with goto in an unstructured language is that when you see a label, you don't know where it came from. It could be anywhere in the entire program (maybe a million lines of code!) And that's a complete disaster. But in a structured language, you know it's from somewhere in the function. And this is no different from any other control structure. You ALWAYS have to look at the whole scope you're in. void foo(){ int n; bool b = true; while (b) { if (n==4) { /* when do we get here? You have to read the whole function to find out. Where does n get modified? */ } : : : } } Heck, even in inline ASM in D, you can't write the kind of spaghetti code Dijkstra was complaining about. You always have local scope. Yet, I personally have been so affected by anti-goto brainwashing that I've never used goto in C, C++, or D. But I gradually realised that it was just brainwashing. I've never experienced any problem with goto in ASM.
 Actually, looking through the DMD source it becomes obvious that goto 
 is really not a problem at all. The lack of comments is much more of a 
 problem. (Especially with files with names like "e2ir.c". What the 
 heck is "fltables.c", "cdxxx.c", "elxxx.c" ?). Even so, it's mostly 
 not that difficult to understand.
I guess Walter has to keep alternating between ASM, C and D. And a lot of ASM coding is nothing more than a bunch of MOV and JMP stuff. And file naming conventions here look like what one typically finds in development code (before some pre-publishing guy has tidyed it up with a lot of global search&replaces). And, after all, the C files never were meant to be public anyway. Actually, the one interesting question might be, would rewriting this code in a structured fashion (I mean, removing the gotos) make it slower? (Not that I'd be suggesting Walter should do it. Just an academic question.)
I doubt it'd affect the speed at all. It'd probably make it longer. There are cases in DMD where it seems to make the control flow simpler.
Apr 22 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Don wrote:
 Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
It'd be really funny to pass it through one of those "code quality" metrics, one of the ones with a ridiculously heavy penalty for using goto. I think it'd tell you that DMD source is almost the lowest-quality code on the planet. <g>
Yeah. But now I'm getting a bad conscience, this is beginning to look like Walter-bashing... :-)
I think those code quality metrics are ridiculous. The prejudice against 'goto' is really just brainwashing and totally without basis.
Well, at the time, they had no choice. Unstructured code was the norm, and people who tangled themselves in spaghetti never noticed it's because of goto usage. Instead they just preceived programming as hard. The language on my first computer was old fashioned BASIC, with line numbers and no named subroutines or structural elements. I felt that the effort needed to program was exponential to the number of lines. In hindsight, that must have been entirely because I'd had no higher education in programming, no notion of structuring the code (in any particular way), etc. But the absolutely worst thing was that one couldn't pass parameters to subroutines. (gosub <lineNumber>) And all variables were global. In those days most programming was done in COBOL, by (essentially) non-programmers. (The idea of COBOL was, after all, to be usable by business people, not MSc programmers.) Jackson had to change not only the methodology, but before that, the concept and the motivation for using structured programming. That was the hard part, and it needed some serious evangelising and brainwashing, to overcome the inertia. Unfortunately, that meant murdering, dismembering, and pulverizing any least hint of even thinking about using goto. And as with any paradigm shift, the disciples took it to religious extremes.
 Here's a recent link from Andrew Koenig, who really should know better.
 
 http://dobbscodetalk.com/index.php?option=com_myblog&show=What-Dijkstra-said-was-harmful-about-goto-state
ents.html&Itemid=29 
 
 Can you see his fundamental mistake? He talks about "the program" (just 
 as Dijkstra said), but it's just not relevant for C/C++/D/Pascal/...
 or any other structured programming language. Wherever he says "program" 
 you should substitute "function". And then the force of the argument 
 totally disappears.
Yes.
 The problem with goto in an unstructured language is that when you see a 
 label, you don't know where it came from. It could be anywhere in the 
 entire program (maybe a million lines of code!) And that's a complete 
 disaster. But in a structured language, you know it's from somewhere in 
 the function.
 And this is no different from any other control structure. You ALWAYS 
 have to look at the whole scope you're in.
 
 void foo(){
  int n;
 bool b = true;
   while (b) {
     if (n==4) {   /* when do we get here? You have to read the whole 
 function to find out. Where does n get modified? */ }
 :
 :
 :
   }
 }
 
 Heck, even in inline ASM in D, you can't write the kind of spaghetti 
 code Dijkstra was complaining about. You always have local scope.
OTOH, getting the algorithm may become tedious even in small snippets. For example, here's Algorithm M, from /Fundamental Algorithms/, Knuth 1969, page 95: M1: int j=n; int k=n; int m=X[n]; M2: if(k==0) goto M6; M3: if(X[k] <= m) goto M5; M4: j=k; m=X[k]; M5: k--; goto M2; M6: ; That's three gotos for six lines. How long did it take to fully figure out what it's doing? Way longer than if it were written in structured D, anyway.
 Yet, I personally have been so affected by anti-goto brainwashing that 
 I've never used goto in C, C++, or D. But I gradually realised that it 
 was just brainwashing. I've never experienced any problem with goto in ASM.
Same here. Last time I used it was in Pascal, and boy, did I have a bad conscience. It felt like I was doing something Mom has forbidden.
 Actually, looking through the DMD source it becomes obvious that goto 
 is really not a problem at all. The lack of comments is much more of 
 a problem. (Especially with files with names like "e2ir.c". What the 
 heck is "fltables.c", "cdxxx.c", "elxxx.c" ?). Even so, it's mostly 
 not that difficult to understand.
I guess Walter has to keep alternating between ASM, C and D. And a lot of ASM coding is nothing more than a bunch of MOV and JMP stuff. And file naming conventions here look like what one typically finds in development code (before some pre-publishing guy has tidyed it up with a lot of global search&replaces). And, after all, the C files never were meant to be public anyway. Actually, the one interesting question might be, would rewriting this code in a structured fashion (I mean, removing the gotos) make it slower? (Not that I'd be suggesting Walter should do it. Just an academic question.)
I doubt it'd affect the speed at all. It'd probably make it longer. There are cases in DMD where it seems to make the control flow simpler.
Simpler, yes. Then again, I'd hate to see folks actually start using goto in D!!!! If Walter uses it, it's different, he's qualified. :-) Oh, (for interested readers,) here's the above code in a test bench: import std.stdio; void main() { enum {DUMMY}; int[] X = [DUMMY,2,3,4,19,18,17,5,1,6]; int n = X.length-1; M1: int j=n; int k=n; int m=X[n]; M2: if(k==0) goto M6; M3: if(X[k] <= m) goto M5; M4: j=k; m=X[k]; M5: k--; goto M2; M6: ; writeln("max: ", m, " pos: ", j); } The dummy and length-1 are needed because, in the old days, especially text books had arrays 1-based. Also numbering things in general used to be 1-based, because "computing culture" hadn't spread to the general public yet. You didn't want to explain all over again the merits of zero based indexing every time you chalked up an example. The interesting part is, still today, this algorithm is essentially what the computer ends up doing, no matter how "structured" our source code was.
Apr 23 2009
parent Charles Hixson <charleshixsn earthlink.net> writes:
Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
It'd be really funny to pass it through one of those "code quality" metrics, one of the ones with a ridiculously heavy penalty for using goto. I think it'd tell you that DMD source is almost the lowest-quality code on the planet. <g>
Yeah. But now I'm getting a bad conscience, this is beginning to look like Walter-bashing... :-)
I think those code quality metrics are ridiculous. The prejudice against 'goto' is really just brainwashing and totally without basis.
Well, at the time, they had no choice. Unstructured code was the norm, and people who tangled themselves in spaghetti never noticed it's because of goto usage. Instead they just preceived programming as hard. The language on my first computer was old fashioned BASIC, with line numbers and no named subroutines or structural elements. I felt that the effort needed to program was exponential to the number of lines. In hindsight, that must have been entirely because I'd had no higher education in programming, no notion of structuring the code (in any particular way), etc. But the absolutely worst thing was that one couldn't pass parameters to subroutines. (gosub <lineNumber>) And all variables were global. In those days most programming was done in COBOL, by (essentially) non-programmers. (The idea of COBOL was, after all, to be usable by business people, not MSc programmers.) Jackson had to change not only the methodology, but before that, the concept and the motivation for using structured programming. That was the hard part, and it needed some serious evangelising and brainwashing, to overcome the inertia. Unfortunately, that meant murdering, dismembering, and pulverizing any least hint of even thinking about using goto. And as with any paradigm shift, the disciples took it to religious extremes.
 Here's a recent link from Andrew Koenig, who really should know better.

 http://dobbscodetalk.com/index.php?option=com_myblog&show=What-Dijkstra-said-was-harmful-about-goto-state
ents.html&Itemid=29 

 Can you see his fundamental mistake? He talks about "the program" 
 (just as Dijkstra said), but it's just not relevant for 
 C/C++/D/Pascal/...
 or any other structured programming language. Wherever he says 
 "program" you should substitute "function". And then the force of the 
 argument totally disappears.
Yes.
 The problem with goto in an unstructured language is that when you see 
 a label, you don't know where it came from. It could be anywhere in 
 the entire program (maybe a million lines of code!) And that's a 
 complete disaster. But in a structured language, you know it's from 
 somewhere in the function.
 And this is no different from any other control structure. You ALWAYS 
 have to look at the whole scope you're in.

 void foo(){
  int n;
 bool b = true;
   while (b) {
     if (n==4) {   /* when do we get here? You have to read the whole 
 function to find out. Where does n get modified? */ }
 :
 :
 :
   }
 }

 Heck, even in inline ASM in D, you can't write the kind of spaghetti 
 code Dijkstra was complaining about. You always have local scope.
OTOH, getting the algorithm may become tedious even in small snippets. For example, here's Algorithm M, from /Fundamental Algorithms/, Knuth 1969, page 95: M1: int j=n; int k=n; int m=X[n]; M2: if(k==0) goto M6; M3: if(X[k] <= m) goto M5; M4: j=k; m=X[k]; M5: k--; goto M2; M6: ; That's three gotos for six lines. How long did it take to fully figure out what it's doing? Way longer than if it were written in structured D, anyway.
 Yet, I personally have been so affected by anti-goto brainwashing that 
 I've never used goto in C, C++, or D. But I gradually realised that it 
 was just brainwashing. I've never experienced any problem with goto in 
 ASM.
Same here. Last time I used it was in Pascal, and boy, did I have a bad conscience. It felt like I was doing something Mom has forbidden.
 Actually, looking through the DMD source it becomes obvious that 
 goto is really not a problem at all. The lack of comments is much 
 more of a problem. (Especially with files with names like "e2ir.c". 
 What the heck is "fltables.c", "cdxxx.c", "elxxx.c" ?). Even so, 
 it's mostly not that difficult to understand.
I guess Walter has to keep alternating between ASM, C and D. And a lot of ASM coding is nothing more than a bunch of MOV and JMP stuff. And file naming conventions here look like what one typically finds in development code (before some pre-publishing guy has tidyed it up with a lot of global search&replaces). And, after all, the C files never were meant to be public anyway. Actually, the one interesting question might be, would rewriting this code in a structured fashion (I mean, removing the gotos) make it slower? (Not that I'd be suggesting Walter should do it. Just an academic question.)
I doubt it'd affect the speed at all. It'd probably make it longer. There are cases in DMD where it seems to make the control flow simpler.
Simpler, yes. Then again, I'd hate to see folks actually start using goto in D!!!! If Walter uses it, it's different, he's qualified. :-) Oh, (for interested readers,) here's the above code in a test bench: import std.stdio; void main() { enum {DUMMY}; int[] X = [DUMMY,2,3,4,19,18,17,5,1,6]; int n = X.length-1; M1: int j=n; int k=n; int m=X[n]; M2: if(k==0) goto M6; M3: if(X[k] <= m) goto M5; M4: j=k; m=X[k]; M5: k--; goto M2; M6: ; writeln("max: ", m, " pos: ", j); } The dummy and length-1 are needed because, in the old days, especially text books had arrays 1-based. Also numbering things in general used to be 1-based, because "computing culture" hadn't spread to the general public yet. You didn't want to explain all over again the merits of zero based indexing every time you chalked up an example. The interesting part is, still today, this algorithm is essentially what the computer ends up doing, no matter how "structured" our source code was.
Even for it's time Basic was a bad language. Fortran was much better, and it existed before Basic was created. (Basic was created as a "simple version" of Fortran. The language was, but using it wasn't.) I still believe, however, that the go to statement should be avoided. Even in small routines. Because they may not stay small. (Doesn't mean you shouldn't ever use it. Sometimes it may actually simplify AND clarify the code. But very rarely. I've only found occasion to actually use it about four times since structured programming features were introduced in the various languages that I use. Generally it can be replaced by a labeled break or continue statement...and even those I've rarely needed since I altered my style to accommodate structures. The one context I used to use the goto in is now handled by exceptions. (Yes, one can argue that a labeled break or continue is effectively a goto, but it is very different in having much more local context. It's limited to a nest of loops rather than to a function.)
Apr 23 2009
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
Georg Wrede wrote:
 
 Actually, the one interesting question might be, would rewriting this 
 code in a structured fashion (I mean, removing the gotos) make it 
 slower? (Not that I'd be suggesting Walter should do it. Just an 
 academic question.)
Yes. For better or worse, goto is sometimes the best way to write efficient code without any duplication.
Apr 22 2009
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
 Yeah. But now I'm getting a bad conscience, this is beginning to look 
 like Walter-bashing... :-)
Don't worry, I'm immune to that. Back in 1984 or so during a code review at work, a colleague grepped for goto and presented a listing of all the gotos with the comment about what a piece of crap my code was. A lot of what I use goto for Andrei has demonstrated can be replaced with scope guards and his enforce template.
Apr 27 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Don, el 22 de abril a las 09:24 me escribiste:
 Georg Wrede wrote:
Walter Bright wrote:
Lutger wrote:
what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
It'd be really funny to pass it through one of those "code quality" metrics, one of the ones with a ridiculously heavy penalty for using goto. I think it'd tell you that DMD source is almost the lowest-quality code on the planet. <g>
Try the Linux kernel. The difference is: a) Well, Linux is a kernel =) b) Gotos are not used gratuitously in the kernel code, they are used to handle error, which is almost the only right way to do it in C. For what I saw for the DMD code that's not true. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- 1950 we were 3 billion people on the earth, today we are 6 billion people
Apr 22 2009
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 Actually, looking through the DMD source it becomes obvious that goto is 
 really not a problem at all. The lack of comments is much more of a 
 problem. (Especially with files with names like "e2ir.c".
e2ir => Expression To Intermediate Representation
 What the heck 
 is "fltables.c", "cdxxx.c", "elxxx.c" ?). Even so, it's mostly not that 
 difficult to understand.
Those are generated by optabgen.exe.
Apr 27 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
I see I was being too obscure. See "Colossus, the Forbin Project" http://us.imdb.com/title/tt0064177/
Apr 27 2009
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Walter Bright wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
I see I was being too obscure. See "Colossus, the Forbin Project" http://us.imdb.com/title/tt0064177/
To clarify: you are *not* 80 feet high and protector of Rhodes?
Apr 27 2009
prev sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Walter Bright wrote:
 Georg Wrede wrote:
 Walter Bright wrote:
 Lutger wrote:
 what the hell...this code can't be human.
I was replaced by Colossus years ago.
Michael A. Jackson wouldn't approve 1175 gotos in 113 files.
I see I was being too obscure. See "Colossus, the Forbin Project" http://us.imdb.com/title/tt0064177/
Heh, by an incredible coincidence, it aired here a couple of weeks ago. Maybe that's why I felt the reference too obvious to comment on. I liked the end. Not what I expected. And more thought provoking like this. It also gave some new depth about understanding the Terminator.
Apr 28 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
 Walter Bright wrote:
 I see I was being too obscure.
 See "Colossus, the Forbin Project" http://us.imdb.com/title/tt0064177/
Heh, by an incredible coincidence, it aired here a couple of weeks ago. Maybe that's why I felt the reference too obvious to comment on.
I think it is an overlooked classic.
Apr 28 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Lars T. Kyllingstad wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work?
I would kill for a 64-bit Linux DMD. I think it could take a lot of ways of coding to a whole new level. Sean and I have also been discussing how to integrate memory-mapped files with the garbage collector. In a 64-bit environment this makes for an awesome programming model. Andrei
Apr 21 2009
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 Lars T. Kyllingstad wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work?
I would kill for a 64-bit Linux DMD. [...]
Who does one have to kill to get a 64-bit compiler around here? :) But seriously, now that the language itself is stabilising, I would consider this a major priority for further development of DMD. 64 bits is the (immediate) future. -Lars
Apr 21 2009
prev sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el 21 de abril a las 07:38 me escribiste:
 Lars T. Kyllingstad wrote:
Walter Bright wrote:
This is a major revision to Phobos, including Andrei's revolutionary new range 
support.

http://www.digitalmars.com/d/2.0/changelog.html
http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work?
I would kill for a 64-bit Linux DMD. I think it could take a lot of ways of coding to a whole new level. Sean and I have also been discussing how to integrate memory-mapped files with the garbage collector. In a 64-bit environment this makes for an awesome programming model.
Can you elaborate on that? Thanks. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ----------------------------------------------------------------------------
Apr 21 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Leandro Lucarella wrote:
 Andrei Alexandrescu, el 21 de abril a las 07:38 me escribiste:
 Lars T. Kyllingstad wrote:
 Walter Bright wrote:
 This is a major revision to Phobos, including Andrei's revolutionary new range 
 support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
This is looking very nice! I want to switch from D1 to D2, but... I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work?
I would kill for a 64-bit Linux DMD. I think it could take a lot of ways of coding to a whole new level. Sean and I have also been discussing how to integrate memory-mapped files with the garbage collector. In a 64-bit environment this makes for an awesome programming model.
Can you elaborate on that?
Not much time, but in short: Memory-mapped files are not a pure library thing, they are core because they manipulate the address space. So they are quite like memory allocation. Unmapping files by hand is as unsafe as calling delete. So memory mapped files must be integrated with the collector: you map a file by hand, and the garbage collector closes it when there are no more references to the memory mapped for the file. The programming model is pretty cool - in 32 bit I always need to mind the address space because it's so densely populated. In 64 bits I can map all of my data files in memory and let the paging system and the garbage collector take care of the rest. Andrei
Apr 21 2009
prev sibling next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Walter Bright wrote:

 
 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Thanks so much, looking good! The lambda template parameters: very cool.
Apr 21 2009
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
Walter Bright wrote:
 
 This is a major revision to Phobos, including Andrei's revolutionary new 
 range support.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Missing from the changelog: From 2.208: 2804 Impure nested functions should be legal inside pure functions From 2.209: std.math: Intrinsics std.math.yl2x and yl2xp1 added. Improves performance of std.math.log() and similar functions (and they are now pure nothrow). (Yes, I know, not very exciting compared to Andrei's new Phobos <g>).
Apr 21 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
  From 2.208:
 2804 Impure nested functions should be legal inside pure functions
Very good. Now that little example works: import std.c.stdio: printf; import std.conv: to; pure int double_sqr(int x) { int y, z; void do_sqr() { y *= y; } y = x; do_sqr(); z += y; y = x; do_sqr(); z += y; return z; } void main(string[] args) { int x = args.length == 2 ? to!(int)(args[1]) : 10; int y = double_sqr(x) + double_sqr(x); printf("4 * x * x = %d\n", y); } The outout is correct: 4 * x * x = 400 "Cleaned up" ASM produced by DMD V.2.029, -O -release -inline: double_sqr: push EAX mov ECX,EAX mov [ESP],0 mov [ESP],ECX imul EAX,[ESP] mov EDX,EAX mov [ESP],EAX mov EAX,ECX mov [ESP],ECX imul EAX,[ESP] add EDX,EAX mov [ESP],EAX mov EAX,EDX pop ECX ret double_sqr.do_sqr: mov ECX,[EAX] imul ECX,[EAX] mov [EAX],ECX ret main: L0: sub ESP,014h cmp dword ptr 018h[ESP],2 jne L21 mov EDX,01Ch[ESP] mov EAX,018h[ESP] mov EAX,8[EDX] mov EDX,0Ch[EDX] push EDX push EAX call near ptr parseString jmp short L26 L21: mov EAX,0Ah L26: call near ptr double_sqr add EAX,EAX mov ECX,offset FLAT:_DATA push EAX push ECX call near ptr printf As you can see there's only one call to double_sqr in the main program, so the pure semantics is working here. You can also see do_sqr is inlined into double_sqr. But the asm code inside double_sqr looks very hairy and long, and double_sqr itself isn't inlined in the main. Bye, bearophile
Apr 21 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
I have tried the following code:

import std.c.stdio: printf;
import std.conv: to;

nothrow pure int double_sqr(int x) { // line 4
    int y, z;
    nothrow void do_sqr() { y *= y; }
    y = x;
    do_sqr();
    z += y;
    y = x;
    do_sqr();
    z += y;
    return z;
}

void main(string[] args) {
    int x = args.length == 2 ? to!(int)(args[1]) : 10;
    int y = double_sqr(x) + double_sqr(x);
    printf("4 * x * x = %d\n", y);
}

The compiler spits the following error:

pure_impure_test.d(4): Error: function pure_impure_test.double_sqr 'double_sqr'
is nothrow yet may throw

but I don't understand why. What are the things inside it that can throw an
exception?

Bye,
bearophile
Apr 21 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
I have also tested the semantics of nested function purity:

import std.c.stdio: printf;
import std.conv: to;

pure int double_sqr(int x) {
    pure int sqr(int y) { return y * y; }
    return sqr(x) + sqr(x);
}

void main(string[] args) {
    int x = args.length == 2 ? to!(int)(args[1]) : 10;
    int y = double_sqr(x) + double_sqr(x);
    printf("4 * x * x = %d\n", y);
}

Compiled without inlining:
-O -release

double_sqr.sqr:
        mov EAX,4[ESP]
        imul    EAX,EAX
        ret 4

double_sqr:
L0:     push    EAX
        push    EAX
        xor EAX,EAX
        call    near ptr double_sqr.sqr
        push    EAX
        sub ESP,4
        xor EAX,EAX
        push    dword ptr 8[ESP]
        call    near ptr double_sqr.sqr
        add ESP,4
        mov ECX,EAX
        pop EAX
        add EAX,ECX
        pop ECX
        ret

main:
L0:     push    EAX
        cmp dword ptr 8[ESP],2
        jne L1D
        mov EDX,0Ch[ESP]
        mov EAX,8[ESP]
        push    dword ptr 0Ch[EDX]
        push    dword ptr 8[EDX]
        call    near ptr to!(int)()
        jmp short   L22
L1D:        mov EAX,0Ah
L22:        call    near ptr double_sqr
        add EAX,EAX
        mov ECX,offset FLAT:_DATA
        push    EAX
        push    ECX
        call    near ptr printf

There's one call to double_sqr but unfortunately two to double_sqr.sqr.

Bye,
bearophile
Apr 21 2009
parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 I have also tested the semantics of nested function purity:
 
 import std.c.stdio: printf;
 import std.conv: to;
 
 pure int double_sqr(int x) {
     pure int sqr(int y) { return y * y; }
     return sqr(x) + sqr(x);
 }
 
 void main(string[] args) {
     int x = args.length == 2 ? to!(int)(args[1]) : 10;
     int y = double_sqr(x) + double_sqr(x);
     printf("4 * x * x = %d\n", y);
 }
 
 Compiled without inlining:
 -O -release
 
 double_sqr.sqr:
         mov EAX,4[ESP]
         imul    EAX,EAX
         ret 4
 
 double_sqr:
 L0:     push    EAX
         push    EAX
         xor EAX,EAX
         call    near ptr double_sqr.sqr
         push    EAX
         sub ESP,4
         xor EAX,EAX
         push    dword ptr 8[ESP]
         call    near ptr double_sqr.sqr
         add ESP,4
         mov ECX,EAX
         pop EAX
         add EAX,ECX
         pop ECX
         ret
 
 main:
 L0:     push    EAX
         cmp dword ptr 8[ESP],2
         jne L1D
         mov EDX,0Ch[ESP]
         mov EAX,8[ESP]
         push    dword ptr 0Ch[EDX]
         push    dword ptr 8[EDX]
         call    near ptr to!(int)()
         jmp short   L22
 L1D:        mov EAX,0Ah
 L22:        call    near ptr double_sqr
         add EAX,EAX
         mov ECX,offset FLAT:_DATA
         push    EAX
         push    ECX
         call    near ptr printf
 
 There's one call to double_sqr but unfortunately two to double_sqr.sqr.
 
 Bye,
 bearophile
Yes. Actually, marking a nested function as pure doesn't make much sense. It's entirely equivalent to moving it outside the function; a nested pure function shouldn't be able to access any members of the enclosing function, otherwise it's not pure. But DMD doesn't enforce that, and so it creates inefficient and possibly buggy code. I'm not sure that nested pure member functions should be legal.
Apr 21 2009
next sibling parent Don <nospam nospam.com> writes:
Don wrote:
 bearophile wrote:
 I have also tested the semantics of nested function purity:

 import std.c.stdio: printf;
 import std.conv: to;

 pure int double_sqr(int x) {
     pure int sqr(int y) { return y * y; }
     return sqr(x) + sqr(x);
 }

 void main(string[] args) {
     int x = args.length == 2 ? to!(int)(args[1]) : 10;
     int y = double_sqr(x) + double_sqr(x);
     printf("4 * x * x = %d\n", y);
 }

 Compiled without inlining:
 -O -release

 double_sqr.sqr:
         mov EAX,4[ESP]
         imul    EAX,EAX
         ret 4

 double_sqr:
 L0:     push    EAX
         push    EAX
         xor EAX,EAX
         call    near ptr double_sqr.sqr
         push    EAX
         sub ESP,4
         xor EAX,EAX
         push    dword ptr 8[ESP]
         call    near ptr double_sqr.sqr
         add ESP,4
         mov ECX,EAX
         pop EAX
         add EAX,ECX
         pop ECX
         ret

 main:
 L0:     push    EAX
         cmp dword ptr 8[ESP],2
         jne L1D
         mov EDX,0Ch[ESP]
         mov EAX,8[ESP]
         push    dword ptr 0Ch[EDX]
         push    dword ptr 8[EDX]
         call    near ptr to!(int)()
         jmp short   L22
 L1D:        mov EAX,0Ah
 L22:        call    near ptr double_sqr
         add EAX,EAX
         mov ECX,offset FLAT:_DATA
         push    EAX
         push    ECX
         call    near ptr printf

 There's one call to double_sqr but unfortunately two to double_sqr.sqr.

 Bye,
 bearophile
Yes. Actually, marking a nested function as pure doesn't make much sense. It's entirely equivalent to moving it outside the function; a nested pure function shouldn't be able to access any members of the enclosing function, otherwise it's not pure. But DMD doesn't enforce that, and so it creates inefficient and possibly buggy code.
The bug is bugzilla 2807.
 I'm not sure that nested pure member functions should be legal.
And it turns out that sqr() isn't actually pure, in the same way that it wasn't nothrow in your first example. The 'pure' marker is silently being ignored. If you put the 'pure' at the end, you get bug 2807. --
Apr 21 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 Yes. Actually, marking a nested function as pure doesn't make much sense.
 It's entirely equivalent to moving it outside the function; [...]
 I'm not sure that nested pure member functions should be legal.
It's not fully equivalent to moving it out of the function because once you pull it out you add a name to the outer namespace: nested functions are useful to keep namespaces tidy too. So I'd like to have nested pure functions too. pure int foo(int y) { return y + y; } // outer foo pure void bar(int x) { pure int foo(int y) { return y * y; } return foo(x) * .foo(x); } Thank you, bye, bearophile
Apr 21 2009
parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 Yes. Actually, marking a nested function as pure doesn't make much sense.
 It's entirely equivalent to moving it outside the function; [...]
 I'm not sure that nested pure member functions should be legal.
It's not fully equivalent to moving it out of the function because once you pull it out you add a name to the outer namespace: nested functions are useful to keep namespaces tidy too. So I'd like to have nested pure functions too. pure int foo(int y) { return y + y; } // outer foo pure void bar(int x) { pure int foo(int y) { return y * y; } return foo(x) * .foo(x); } Thank you, bye, bearophile
That's true, but it seems quite difficult to get right. A pure nested function can in theory access immutable members in the outer function -- but must not access the parameters of the outer function. If there are no immutable members in the outer function, the compiler would ideally convert it into an external pure function, so that it doesn't need a frame pointer to the outer function. But it would need error messages for any use of mutable outer function members. Etc. It seems quite a lot of work for something of very limited use. Making it into a external, private pure function is almost the same.
Apr 21 2009
next sibling parent Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Tue, Apr 21, 2009 at 8:56 PM, Don <nospam nospam.com> wrote:
 bearophile wrote:
 Don:
 Yes. Actually, marking a nested function as pure doesn't make much sens=
e.
 It's entirely equivalent to moving it outside the function; [...]
 I'm not sure that nested pure member functions should be legal.
It's not fully equivalent to moving it out of the function because once you pull it out you add a name to the outer namespace: nested functions =
are
 useful to keep namespaces tidy too.
 So I'd like to have nested pure functions too.

 pure int foo(int y) { return y + y; } // outer foo
 pure void bar(int x) {
 =C2=A0pure int foo(int y) { return y * y; }
 =C2=A0return foo(x) * .foo(x);
 }

 Thank you,
 bye,
 bearophile
That's true, but it seems quite difficult to get right. A pure nested function can in theory access immutable members in the outer function -- =
but
 must not access the parameters of the outer function.
 If there are no immutable members in the outer function, the compiler wou=
ld
 ideally convert it into an external pure function, so that it
 doesn't need a frame pointer to the outer function. But it would need err=
or
 messages for any use of mutable outer function members. Etc.
 It seems quite a lot of work for something of very limited use.
 Making it into a external, private pure function is almost the same.
why not just make it a static pure nested function? or is that no longer proper D2 ?
Apr 21 2009
prev sibling parent reply Don <nospam nospam.com> writes:
Don wrote:
 bearophile wrote:
 Don:
 Yes. Actually, marking a nested function as pure doesn't make much 
 sense.
 It's entirely equivalent to moving it outside the function; [...]
 I'm not sure that nested pure member functions should be legal.
It's not fully equivalent to moving it out of the function because once you pull it out you add a name to the outer namespace: nested functions are useful to keep namespaces tidy too. So I'd like to have nested pure functions too. pure int foo(int y) { return y + y; } // outer foo pure void bar(int x) { pure int foo(int y) { return y * y; } return foo(x) * .foo(x); } Thank you, bye, bearophile
That's true, but it seems quite difficult to get right. A pure nested function can in theory access immutable members in the outer function -- but must not access the parameters of the outer function. If there are no immutable members in the outer function, the compiler would ideally convert it into an external pure function, so that it doesn't need a frame pointer to the outer function. But it would need error messages for any use of mutable outer function members. Etc. It seems quite a lot of work for something of very limited use. Making it into a external, private pure function is almost the same.
Actually it's not so difficult. I've created a patch for bug 2807 -- it's only 5 lines long! It gives an error message if a nested pure function accesses a mutable variable from an outer scope.
Apr 22 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 Actually it's not so difficult. I've created a patch for bug 2807 -- 
 it's only 5 lines long! It gives an error message if a nested pure 
 function accesses a mutable variable from an outer scope.
Thank you very much Don, your work helps a lot. Every time I try a tiny program I find something I don't understand: import std.stdio: writeln; import std.math: sqrt; import std.conv: to; void main(string[] args) { double x = args.length == 2 ? to!(double)(args[1]) : 4.0; writeln(sqrt(x) + sqrt(x)); } I have also tried with std.math.sin with similar results: L0: enter 8,0 mov EAX,8[EBP] cmp EAX,2 jne L30 cmp EAX,1 ja L1B mov EAX,6 call near ptr _D6test7__arrayZ L1B: mov EDX,0Ch[EBP] mov EAX,8[EBP] mov EAX,8[EDX] mov EDX,0Ch[EDX] push EDX push EAX call near ptr _D3std4conv13__T2toTdTAyaZ2toFAyaZd jmp short L36 L30: fld qword ptr FLAT:_DATA[00h] L36: fstp qword ptr -8[EBP] fld qword ptr -8[EBP] fsin fld qword ptr -8[EBP] fsin faddp ST(1),ST sub ESP,0Ch fstp tbyte ptr [ESP] call near ptr _D3std5stdio14__T7writelnTeZ7writelnFeZv xor EAX,EAX leave ret Isn't sin(x)+sin(x) pure? Even if the compiler doesn't want to replace x+x with x*2 because x is a floating point, it can do: y = sin(x) y+y And that gives the same result even with FPs. Note: with SSE2 it's even possible to perform two sqrt(double) at the same time, so a compiler can implement sin(x)+sin(y) with a single instruction (SQRTSD) (plus eventually some register loading/unloading). Bye, bearophile
Apr 22 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
bearophile:
 so a compiler can implement sin(x)+sin(y) with a single instruction (SQRTSD)
I meant sqrt(x)+sqrt(y), sorry.
Apr 22 2009
prev sibling parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 Actually it's not so difficult. I've created a patch for bug 2807 -- 
 it's only 5 lines long! It gives an error message if a nested pure 
 function accesses a mutable variable from an outer scope.
Thank you very much Don, your work helps a lot. Every time I try a tiny program I find something I don't understand: import std.stdio: writeln; import std.math: sqrt; import std.conv: to; void main(string[] args) { double x = args.length == 2 ? to!(double)(args[1]) : 4.0; writeln(sqrt(x) + sqrt(x)); } I have also tried with std.math.sin with similar results: L0: enter 8,0 mov EAX,8[EBP] cmp EAX,2 jne L30 cmp EAX,1 ja L1B mov EAX,6 call near ptr _D6test7__arrayZ L1B: mov EDX,0Ch[EBP] mov EAX,8[EBP] mov EAX,8[EDX] mov EDX,0Ch[EDX] push EDX push EAX call near ptr _D3std4conv13__T2toTdTAyaZ2toFAyaZd jmp short L36 L30: fld qword ptr FLAT:_DATA[00h] L36: fstp qword ptr -8[EBP] fld qword ptr -8[EBP] fsin fld qword ptr -8[EBP] fsin faddp ST(1),ST sub ESP,0Ch fstp tbyte ptr [ESP] call near ptr _D3std5stdio14__T7writelnTeZ7writelnFeZv xor EAX,EAX leave ret Isn't sin(x)+sin(x) pure? Even if the compiler doesn't want to replace x+x with x*2 because x is a floating point, it can do: y = sin(x) y+y And that gives the same result even with FPs.
Yes. From further investigation, I've found that: (1) the optimisation of pure only happens for int returns, not for floating-point return types. It should convert purefunc(x)+purefunc(x) into 2*purefunc(x) if the return type of purefunc is int, float, or complex. (2) the back-end isn't smart enough to convert f*2 into f+f. It's difficult to work out where it's optimising the int return. I can see where it marks pure calls as subexpressions to be potentially eliminated: OTae(op) is true in gflow.c(660) if it's a pure call, false if it's an impure call. The problem may simply be that the backend doesn't do much common subexpression elimination of floating-point expressions. I really don't understand the backend. It's quite cryptic. Key acronyms are AE, CP and VBE. Then there's Bin, Bgen, Bkill, etc. AE *might* be Available Expression (but what does that mean?) CP might be Copy Propagation info I've found that VBE = "Very Busy Expression"! (what does that mean?) Fixing your problem is beyond me at present, I think.
Apr 23 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 I really don't understand the backend. It's quite cryptic. Key acronyms 
 are AE, CP and VBE. Then there's Bin, Bgen, Bkill, etc.
 AE *might* be Available Expression (but what does that mean?)
 CP might be Copy Propagation info
 I've found that VBE = "Very Busy Expression"! (what does that mean?)
I suggest to add comments to the DMD source code every time a small mystery is revealed, to rename the files once a much better name is found, to improve and refactor the code every time it a good thing to do it. Every time you put your hand in the code you can improve the code locally and leave it better then before (this is the Scout principle in programming). Then such patches/changes can be slowly folded back into DMD and with time the sources will improve and will become more readable. Once they can be understood better, further changes become faster and simpler. Bye, bearophile
Apr 23 2009
parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 I really don't understand the backend. It's quite cryptic. Key acronyms 
 are AE, CP and VBE. Then there's Bin, Bgen, Bkill, etc.
 AE *might* be Available Expression (but what does that mean?)
 CP might be Copy Propagation info
 I've found that VBE = "Very Busy Expression"! (what does that mean?)
I suggest to add comments to the DMD source code every time a small mystery is revealed, to rename the files once a much better name is found, to improve and refactor the code every time it a good thing to do it. Every time you put your hand in the code you can improve the code locally and leave it better then before (this is the Scout principle in programming). Then such patches/changes can be slowly folded back into DMD and with time the sources will improve and will become more readable. Once they can be understood better, further changes become faster and simpler.
I'd love to do that, but unfortunately it's not easy to get _any_ changes into DMD. Only Walter has write-access to it, and AFAIK he checks every line and enters it manually. Like Linus was famous for doing with the Linux kernel.
 
 Bye,
 bearophile
Apr 23 2009
parent Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Thu, Apr 23, 2009 at 2:37 PM, Don <nospam nospam.com> wrote:
 bearophile wrote:
 Don:
 I really don't understand the backend. It's quite cryptic. Key acronyms
 are AE, CP and VBE. Then there's Bin, Bgen, Bkill, etc.
 AE *might* be Available Expression (but what does that mean?)
 CP might be Copy Propagation info
 I've found that VBE = "Very Busy Expression"! (what does that mean?)
I suggest to add comments to the DMD source code every time a small mystery is revealed, to rename the files once a much better name is found, to improve and refactor the code every time it a good thing to do it. Every time you put your hand in the code you can improve the code locally and leave it better then before (this is the Scout principle in programming). Then such patches/changes can be slowly folded back into DMD and with time the sources will improve and will become more readable. Once they can be understood better, further changes become faster and simpler.
I'd love to do that, but unfortunately it's not easy to get _any_ changes into DMD. Only Walter has write-access to it, and AFAIK he checks every line and enters it manually. Like Linus was famous for doing with the Linux kernel.
Glad to hear I'm not the only one with that impression...
Apr 23 2009
prev sibling parent Don <nospam nospam.com> writes:
Don wrote:
 bearophile wrote:
 Isn't sin(x)+sin(x) pure? Even if the compiler doesn't want to replace 
 x+x with x*2 because x is a floating point, it can do:

 y = sin(x)
 y+y

 And that gives the same result even with FPs.
Yes. From further investigation, I've found that: (1) the optimisation of pure only happens for int returns, not for floating-point return types. It should convert purefunc(x)+purefunc(x) into 2*purefunc(x) if the return type of purefunc is int, float, or complex. (2) the back-end isn't smart enough to convert f*2 into f+f.
I've fixed (2), patch to the backend is in bigzilla 2888. I learnt a lot about the backend in the process, maybe I can fix (1) now.
Apr 25 2009
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-04-21 11:18:39 -0400, Don <nospam nospam.com> said:

 Yes. Actually, marking a nested function as pure doesn't make much sense.
 It's entirely equivalent to moving it outside the function; a nested 
 pure function shouldn't be able to access any members of the enclosing 
 function, otherwise it's not pure. But DMD doesn't enforce that, and so 
 it creates inefficient and possibly buggy code.
What about immutable local variables? A pure function can access immutable globals, so it should be able to access immutable locals too. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 21 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Michel Fortin wrote:
 On 2009-04-21 11:18:39 -0400, Don <nospam nospam.com> said:
 
 Yes. Actually, marking a nested function as pure doesn't make much sense.
 It's entirely equivalent to moving it outside the function; a nested
 pure function shouldn't be able to access any members of the enclosing
 function, otherwise it's not pure. But DMD doesn't enforce that, and
 so it creates inefficient and possibly buggy code.
What about immutable local variables? A pure function can access immutable globals, so it should be able to access immutable locals too.
If you treat the nested function's context pointer as a pointer to a struct matching the stack layout, then you can have pure nested functions -- they have exactly the same semantics as a pure struct member function. -- Daniel
Apr 21 2009
parent reply Don <nospam nospam.com> writes:
Daniel Keep wrote:
 
 Michel Fortin wrote:
 On 2009-04-21 11:18:39 -0400, Don <nospam nospam.com> said:

 Yes. Actually, marking a nested function as pure doesn't make much sense.
 It's entirely equivalent to moving it outside the function; a nested
 pure function shouldn't be able to access any members of the enclosing
 function, otherwise it's not pure. But DMD doesn't enforce that, and
 so it creates inefficient and possibly buggy code.
What about immutable local variables? A pure function can access immutable globals, so it should be able to access immutable locals too.
If you treat the nested function's context pointer as a pointer to a struct matching the stack layout, then you can have pure nested functions -- they have exactly the same semantics as a pure struct member function. -- Daniel
True, but that would mean that it'd be pretty useless. It's almost exactly the same as not marking it pure. pure foo(int x) { int y; pure int bar(int z) { return z*z; } int a= bar(2); y++; int b = bar(2); // has to recalculate bar(2), because y has changed. } --- The basic issue is that the situations where marking a nested function as 'pure' is a good idea, is extremely limited. Compared to making it an external pure private function, with any desired immutable members passed as parameters, it has these advantages and disadvantages. + inaccessable to other functions in the same module. + can access immutable members in the outer function, without passing them as parameters. - slower, since it needs a context pointer as well as a frame pointer. I think those benefits are pathetic.
Apr 22 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 22 Apr 2009 03:12:04 -0400, Don <nospam nospam.com> wrote:

 Daniel Keep wrote:
  Michel Fortin wrote:
 On 2009-04-21 11:18:39 -0400, Don <nospam nospam.com> said:

 Yes. Actually, marking a nested function as pure doesn't make much  
 sense.
 It's entirely equivalent to moving it outside the function; a nested
 pure function shouldn't be able to access any members of the enclosing
 function, otherwise it's not pure. But DMD doesn't enforce that, and
 so it creates inefficient and possibly buggy code.
What about immutable local variables? A pure function can access immutable globals, so it should be able to access immutable locals too.
If you treat the nested function's context pointer as a pointer to a struct matching the stack layout, then you can have pure nested functions -- they have exactly the same semantics as a pure struct member function. -- Daniel
True, but that would mean that it'd be pretty useless. It's almost exactly the same as not marking it pure. pure foo(int x) { int y; pure int bar(int z) { return z*z; } int a= bar(2); y++; int b = bar(2); // has to recalculate bar(2), because y has changed. } --- The basic issue is that the situations where marking a nested function as 'pure' is a good idea, is extremely limited. Compared to making it an external pure private function, with any desired immutable members passed as parameters, it has these advantages and disadvantages. + inaccessable to other functions in the same module. + can access immutable members in the outer function, without passing them as parameters. - slower, since it needs a context pointer as well as a frame pointer. I think those benefits are pathetic.
What about treating nested functions of pure functions like a logical grouping of statements within the function? That is, when you call a nested function inside a pure function, the call can't be optimized, but any calls the nested function makes (to a global pure function) can be optimized, and the nested function still provides the same guarantees (cannot access any globals, must only call other pure functions), however it can access and modify locals within the outer function. I use nested functions a lot not as mini functions within a function but as simple ways to avoid duplicating code everywhere in my function. You probably couldn't allow taking a delegate of such a function either. -Steve
Apr 22 2009
parent Don <nospam nospam.com> writes:
Steven Schveighoffer wrote:
 On Wed, 22 Apr 2009 03:12:04 -0400, Don <nospam nospam.com> wrote:
 
 Daniel Keep wrote:
  Michel Fortin wrote:
 On 2009-04-21 11:18:39 -0400, Don <nospam nospam.com> said:

 Yes. Actually, marking a nested function as pure doesn't make much 
 sense.
 It's entirely equivalent to moving it outside the function; a nested
 pure function shouldn't be able to access any members of the enclosing
 function, otherwise it's not pure. But DMD doesn't enforce that, and
 so it creates inefficient and possibly buggy code.
What about immutable local variables? A pure function can access immutable globals, so it should be able to access immutable locals too.
If you treat the nested function's context pointer as a pointer to a struct matching the stack layout, then you can have pure nested functions -- they have exactly the same semantics as a pure struct member function. -- Daniel
True, but that would mean that it'd be pretty useless. It's almost exactly the same as not marking it pure. pure foo(int x) { int y; pure int bar(int z) { return z*z; } int a= bar(2); y++; int b = bar(2); // has to recalculate bar(2), because y has changed. } --- The basic issue is that the situations where marking a nested function as 'pure' is a good idea, is extremely limited. Compared to making it an external pure private function, with any desired immutable members passed as parameters, it has these advantages and disadvantages. + inaccessable to other functions in the same module. + can access immutable members in the outer function, without passing them as parameters. - slower, since it needs a context pointer as well as a frame pointer. I think those benefits are pathetic.
What about treating nested functions of pure functions like a logical grouping of statements within the function? That is, when you call a nested function inside a pure function, the call can't be optimized, but any calls the nested function makes (to a global pure function) can be optimized, and the nested function still provides the same guarantees (cannot access any globals, must only call other pure functions), however it can access and modify locals within the outer function.
That's exactly what my recent change (2804) did.
 I use nested functions a lot not as mini functions within a function but 
 as simple ways to avoid duplicating code everywhere in my function.
 
 You probably couldn't allow taking a delegate of such a function either.
I've just submitted a patch (2695) which makes usage of function pointers and delegates safe within pure functions. Basically, you can take the delegate of a nested function, but you can't call it. You could return it, but I believe that's OK, because it should become a closure. I'm on a quest to make 'pure' usable in D <g>.
Apr 22 2009
prev sibling parent Don <nospam nospam.com> writes:
bearophile wrote:
 I have tried the following code:
 
 import std.c.stdio: printf;
 import std.conv: to;
 
 nothrow pure int double_sqr(int x) { // line 4
     int y, z;
     nothrow void do_sqr() { y *= y; }
     y = x;
     do_sqr();
     z += y;
     y = x;
     do_sqr();
     z += y;
     return z;
 }
 
 void main(string[] args) {
     int x = args.length == 2 ? to!(int)(args[1]) : 10;
     int y = double_sqr(x) + double_sqr(x);
     printf("4 * x * x = %d\n", y);
 }
 
 The compiler spits the following error:
 
 pure_impure_test.d(4): Error: function pure_impure_test.double_sqr
'double_sqr' is nothrow yet may throw
 
 but I don't understand why. What are the things inside it that can throw an
exception?
 
 Bye,
 bearophile
Obviously my 2808 patch only solved one part of the problem. It compiles if you change do_sqr to void do_sqr() nothrow { y *= y; } Please add a bug report to Bugzilla.
Apr 21 2009
prev sibling next sibling parent reply tama <repeatedly gmail.com> writes:
On Mon, 20 Apr 2009 16:09:09 +0900, Walter Bright  
<newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary new  
 range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Range is so cool! Though... I tried following code: void main() { writeln("Case1"); { Mt19937 gen = Mt19937(0); writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen = Mt19937(0); advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("(J\(BnCase2"); { Mt19937 gen; writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen; advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } } Result: Case1 2357136044 (1) 2546248239 (2) --- 2546248239 (2) 3071714933 (3) Case2 581869302 (1) 3890346734 (2) --- 581869302 (1)? 3890346734 (2)? I think 'Case1' is correct, but 'Case2' is wrong. Mt19937's bug? -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/ $B%a%s%P!<Jg=8Cf(B http://tpf.techtalk.jp/
Apr 21 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
tama wrote:
 On Mon, 20 Apr 2009 16:09:09 +0900, Walter Bright 
 <newshound1 digitalmars.com> wrote:
 
 This is a major revision to Phobos, including Andrei's revolutionary 
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Range is so cool! Though... I tried following code: void main() { writeln("Case1"); { Mt19937 gen = Mt19937(0); writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen = Mt19937(0); advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("\nCase2"); { Mt19937 gen; writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen; advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } } Result: Case1 2357136044 (1) 2546248239 (2) --- 2546248239 (2) 3071714933 (3) Case2 581869302 (1) 3890346734 (2) --- 581869302 (1)? 3890346734 (2)? I think 'Case1' is correct, but 'Case2' is wrong. Mt19937's bug?
If you initialize the Mersenne twister with no seed it will start with seed 5489u. Andrei
Apr 22 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 22 Apr 2009 13:49:18 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 tama wrote:
 On Mon, 20 Apr 2009 16:09:09 +0900, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Range is so cool! Though... I tried following code: void main() { writeln("Case1"); { Mt19937 gen = Mt19937(0); writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen = Mt19937(0); advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("\nCase2"); { Mt19937 gen; writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen; advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } } Result: Case1 2357136044 (1) 2546248239 (2) --- 2546248239 (2) 3071714933 (3) Case2 581869302 (1) 3890346734 (2) --- 581869302 (1)? 3890346734 (2)? I think 'Case1' is correct, but 'Case2' is wrong. Mt19937's bug?
If you initialize the Mersenne twister with no seed it will start with seed 5489u.
I think his point is in the second part of Case2, he skipped one element, but it appears that it didn't skip anything. -Steve
Apr 22 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 On Wed, 22 Apr 2009 13:49:18 -0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 tama wrote:
 On Mon, 20 Apr 2009 16:09:09 +0900, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Range is so cool! Though... I tried following code: void main() { writeln("Case1"); { Mt19937 gen = Mt19937(0); writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen = Mt19937(0); advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("\nCase2"); { Mt19937 gen; writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen; advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } } Result: Case1 2357136044 (1) 2546248239 (2) --- 2546248239 (2) 3071714933 (3) Case2 581869302 (1) 3890346734 (2) --- 581869302 (1)? 3890346734 (2)? I think 'Case1' is correct, but 'Case2' is wrong. Mt19937's bug?
If you initialize the Mersenne twister with no seed it will start with seed 5489u.
I think his point is in the second part of Case2, he skipped one element, but it appears that it didn't skip anything.
Oh ok, thanks tama and Steve. I know where the problem is (on the Mersenne twister, if you call popFront without ever calling head there's a bug). Could you submit a bug? I'm on battery and on short time, and Walter is bugging me :o). Andrei
Apr 22 2009
parent reply "Masahiro Nakagawa" <repeatedly gmail.com> writes:
On Thu, 23 Apr 2009 03:12:16 +0900, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 On Wed, 22 Apr 2009 13:49:18 -0400, Andrei Alexandrescu  
 <SeeWebsiteForEmail erdani.org> wrote:

 tama wrote:
 On Mon, 20 Apr 2009 16:09:09 +0900, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Range is so cool! Though... I tried following code: void main() { writeln("Case1"); { Mt19937 gen = Mt19937(0); writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen = Mt19937(0); advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("\nCase2"); { Mt19937 gen; writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen; advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } } Result: Case1 2357136044 (1) 2546248239 (2) --- 2546248239 (2) 3071714933 (3) Case2 581869302 (1) 3890346734 (2) --- 581869302 (1)? 3890346734 (2)? I think 'Case1' is correct, but 'Case2' is wrong. Mt19937's bug?
If you initialize the Mersenne twister with no seed it will start with seed 5489u.
I think his point is in the second part of Case2, he skipped one element, but it appears that it didn't skip anything.
Oh ok, thanks tama and Steve. I know where the problem is (on the Mersenne twister, if you call popFront without ever calling head there's a bug). Could you submit a bug? I'm on battery and on short time, and Walter is bugging me :o).
I submitted this problem to bugzilla. http://d.puremagic.com/issues/show_bug.cgi?id=2882 -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/
Apr 22 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Masahiro Nakagawa wrote:
 I submitted this problem to bugzilla.
 http://d.puremagic.com/issues/show_bug.cgi?id=2882
Thanks! I fixed it and checked in std.random. Andrei
Apr 23 2009
parent "Masahiro Nakagawa" <repeatedly gmail.com> writes:
On Thu, 23 Apr 2009 18:09:06 +0900, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Masahiro Nakagawa wrote:
 I submitted this problem to bugzilla.
 http://d.puremagic.com/issues/show_bug.cgi?id=2882
Thanks! I fixed it and checked in std.random.
Wow! std.random in svn works fine. Thanks for your quick response. -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/
Apr 23 2009
prev sibling parent "Masahiro Nakagawa" <repeatedly gmail.com> writes:
Changed sender name from screen name to real name.

On Thu, 23 Apr 2009 02:55:37 +0900, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:
 On Wed, 22 Apr 2009 13:49:18 -0400, Andrei Alexandrescu  
 <SeeWebsiteForEmail erdani.org> wrote:

 tama wrote:
 On Mon, 20 Apr 2009 16:09:09 +0900, Walter Bright
 <newshound1 digitalmars.com> wrote:

 This is a major revision to Phobos, including Andrei's revolutionary
 new range support.

 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.029.zip
Range is so cool! Though... I tried following code: void main() { writeln("Case1"); { Mt19937 gen = Mt19937(0); writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen = Mt19937(0); advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("\nCase2"); { Mt19937 gen; writeln(gen.front); gen.popFront; writeln(gen.front); } writeln("---"); { Mt19937 gen; advance(gen, 1); // skip 1 element writeln(gen.front); gen.popFront; writeln(gen.front); } } Result: Case1 2357136044 (1) 2546248239 (2) --- 2546248239 (2) 3071714933 (3) Case2 581869302 (1) 3890346734 (2) --- 581869302 (1)? 3890346734 (2)? I think 'Case1' is correct, but 'Case2' is wrong. Mt19937's bug?
If you initialize the Mersenne twister with no seed it will start with seed 5489u.
I think his point is in the second part of Case2, he skipped one element, but it appears that it didn't skip anything.
Thanks for your comment. Lack of talk about this problem:| -- tama <repeatedly gmail.com> http://profile.livedoor.com/repeatedly/
Apr 22 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
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
Apr 23 2009
parent reply Don <nospam nospam.com> writes:
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
Apr 23 2009
next sibling parent grauzone <none example.net> writes:
 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.)
Apr 23 2009
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
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
Apr 23 2009
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
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!
Apr 23 2009
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Denis Koroskin wrote:
 On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam 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. 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. 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) Though I suppose you could take a delegate to toString in the default format method and see if the function pointer in it points to Object.toString, just calling sink(this.classinfo.name) if so (to emulate current behavior), and calling toString() if not... (Or maybe the other way around; have Object.toString check if the format function was overridden, call it if so and return the classname if not)
Apr 23 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Frits van Bommel wrote:
 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.
Yah. The way std.format does it is by operating on an abstract output range, and then have Appender!(T[]) implement the output range interface. So getting stringizing is as easy as passing an Appender!string in there.
 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.
Probably we'll need that. You forgot the "in" though :o). Andrei
Apr 23 2009
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Andrei Alexandrescu wrote:
 Frits van Bommel wrote:
 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.
Probably we'll need that. You forgot the "in" though :o).
That's just because I'm thinking in D1, where it's optional :).
Apr 23 2009
prev sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 23 Apr 2009 17:35:59 +0400, Frits van Bommel
<fvbommel remwovexcapss.nl> wrote:

 Denis Koroskin wrote:
 On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam 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.
Apr 23 2009
next sibling parent grauzone <none example.net> writes:
 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.
Needs simple converter code, that safe you from typing trivial stuff like this: toString((char[] s) { writeln(s); });
     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);
The idea is to add a format() function that takes sink() for output: std.string.format(sink, yourformat, _number);
 Besides, why is it called toString(), if it doesn't give me an object's string
representation???
Should be called debug_output() or something similar.
Apr 23 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 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.
I hear you, but there are quite a few more considerations that apply. For one, making string the common format of all objects is pretty hamfisted. We need to integrate things like binary streams too. Second, using string append and composing with it is bound to be inefficient, and for multiple reasons. You can't just say that a reasonable way to print a matrix is to call toString against it and print the resulting string. With the temporary buffer passed-in or not, that's just a terrible design. But you need not fear. Converting to string will remain easy and simple, it will only be a particular case of streaming objects out. Andrei
Apr 23 2009
parent "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 23 Apr 2009 18:28:53 +0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 Denis Koroskin wrote:
 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.
I hear you, but there are quite a few more considerations that apply. For one, making string the common format of all objects is pretty hamfisted. We need to integrate things like binary streams too. Second, using string append and composing with it is bound to be inefficient, and for multiple reasons. You can't just say that a reasonable way to print a matrix is to call toString against it and print the resulting string. With the temporary buffer passed-in or not, that's just a terrible design. But you need not fear. Converting to string will remain easy and simple, it will only be a particular case of streaming objects out. Andrei
I'm fine with that, especially if entire Phobos will be consistent with it (e.g. std.string.format accepts sink object etc). There a few problems with it, though. I like the "toStream" name but I believe it is a bit misleading - if toString() returns a string, then toStream() should return stream, too, not accept it. But what about custom formatting? Previously I stated that current scheme doesn't allow them, but it turned out to be possible. For example, you introduced custom array formatting: %(s; ) -> array.toString("s; ", ...); Similar approach may be used for other user-defined formatting options: %s -> obj.toString("s"); %d -> obj.toString("d"); ... %(any_set_of_characters) -> obj.toString("any_set_of_characters"); // including inner %() etc Example: given an array of arrays of ints, print them as follows: "[ [1, 2, 3, 4, ]; [5, 6, 7, 8, ]; [9, a, b, c, ]; ]" int[][] arrayOfArraysOfInts; writefln("[ %([%(x, )]; )]", arrayOfArraysOfInts); Just to make it more clear: [ %([%(x, )]; )] -> "[ " ~ arrayOfArraysOfInts.toString("[%(x, )]; ") ~ "]"
Apr 23 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Apr 23 2009
next sibling parent reply grauzone <none example.net> writes:
 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?
Apr 23 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Apr 23 2009
parent reply grauzone <none example.net> writes:
Andrei Alexandrescu wrote:
 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?
?
Why make it more complicated than it has to be? Also, I don't know ranges, but your example doesn't seem to make much sense.
 Andrei
Apr 23 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
grauzone wrote:
 Andrei Alexandrescu wrote:
 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?
?
Why make it more complicated than it has to be?
I am making it simpler.
 Also, I don't know ranges, but your example doesn't seem to make much 
 sense.
s/but/consequently/ Andrei
Apr 23 2009
parent reply grauzone <none example.net> writes:
Andrei Alexandrescu wrote:
 grauzone wrote:
 Andrei Alexandrescu wrote:
 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?
?
Why make it more complicated than it has to be?
I am making it simpler.
How is it simpler? sink(): simple delegate with the signature void delegate(char[] data); output range: um what...? yeah, I know it has a put() method that takes... something. What exactly is it supposed to take in your example? Is streamOut() a method of the object to be dumped? What exact types to T and R have? (You need the exact type if streamOut is supposed to be a member function, and thus has to be virtual, so that you can it use like the Object.toString method.)
 Also, I don't know ranges, but your example doesn't seem to make much 
 sense.
s/but/consequently/
Probably. Just imagine you had to explain it to someone who's new to D. Actually, I _am_ new to D2.0. So, um... what is a b c and T object?
 
 Andrei
Apr 23 2009
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
grauzone wrote:

 void streamOut(T, R)(T object, R range)
 {
     foreach(x; a) range.put(x);
     range.put(b);
     range.put(c);
 }
So, um... what is a b c and T object?
In my opinion, this is a confusing example. I believe it was meant to be: void streamOut(T, R)(T object, R range) { foreach(x; object.a) range.put(x); range.put(object.b); range.put(object.c); } So, streamOut is a free function, which it normally would not be. Now, consider this: struct foo { int[] a; bool b; char c; void streamOut(R)(R range) { foreach(x; a) range.put(x); range.put(b); range.put(c); } } I believe this is what you'd normally do. Do note that I might have misinterpreted it all, as Andrei's code would not do what I have outlined above, I only feel it makes the most sense. -- Simen
Apr 24 2009
parent reply grauzone <none example.net> writes:
Simen Kjaeraas wrote:
 grauzone wrote:
 
 void streamOut(T, R)(T object, R range)
 {
     foreach(x; a) range.put(x);
     range.put(b);
     range.put(c);
 }
So, um... what is a b c and T object?
In my opinion, this is a confusing example. I believe it was meant to be: void streamOut(T, R)(T object, R range) { foreach(x; object.a) range.put(x); range.put(object.b); range.put(object.c); } So, streamOut is a free function, which it normally would not be. Now, consider this: struct foo { int[] a; bool b; char c; void streamOut(R)(R range) { foreach(x; a) range.put(x); range.put(b); range.put(c); } } I believe this is what you'd normally do. Do note that I might have misinterpreted it all, as Andrei's code would not do what I have outlined above, I only feel it makes the most sense.
Yeah OK, but what about virtual functions? Not having it virtual is a real disadvantage, because subclass-parts aren't automatically dumped. What exactly is R, and why is it simpler than a Sink delegate? A Sink delegate is as simple as it gets, and what else than a string do you want to output? (Hint: this is probably not supposed to be a serialization framework.) One thing that I could imagine that put() automatically takes care of formatting various data types into a string. Okay, where can I pass format specifiers? What if put() can't deal with the type? Or does it call std.string.format() anyway? Then why the indirection through the string? Why not call format() directly? (Yes, format() needs to be able to output using a sink instead of returning a string.) Oh by the way, unlike a weird template, sink works with virtual methods, too. I have the impression Andrei wants to cast everything into ranges instead of adhering to KISS.
 -- 
  Simen
Apr 24 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
grauzone wrote:
 Simen Kjaeraas wrote:
 Do note that I might have misinterpreted it all, as Andrei's code 
 would not do what I have outlined above, I only feel it makes the most 
 sense.
Yeah OK, but what about virtual functions? Not having it virtual is a real disadvantage, because subclass-parts aren't automatically dumped.
Streaming out is a virtual function that takes a classic interface object. (I explained that in two posts.)
 What exactly is R, and why is it simpler than a Sink delegate? A Sink 
 delegate is as simple as it gets, and what else than a string do you 
 want to output? (Hint: this is probably not supposed to be a 
 serialization framework.)
It is simpler than a Sink delegate because the delegate is not simple; it's simplistic. You can't use std.algorithm with a delegate, it only accepts one type (meaning it is very inefficient if you have multiple types to output) - it's essentially a non-design.
 One thing that I could imagine that put() automatically takes care of 
 formatting various data types into a string. Okay, where can I pass 
 format specifiers? What if put() can't deal with the type? Or does it 
 call std.string.format() anyway? Then why the indirection through the 
 string? Why not call format() directly? (Yes, format() needs to be able 
 to output using a sink instead of returning a string.)
I'd spend more time on explaining that but I fear you want more to convince yourself and others that output streams are no good and that your non-design is simpler, than actually getting answers to your questions.
 Oh by the way, unlike a weird template, sink works with virtual methods, 
 too.
 
 I have the impression Andrei wants to cast everything into ranges 
 instead of adhering to KISS.
I want to adhere to KISS, and therefore I want to support output ranges with e.g. strings and files. If you don't take the time to look at ranges as you yourself said, then why do you spend time commenting on them? Shouldn't things go the other way? Andrei
Apr 24 2009
next sibling parent grauzone <none example.net> writes:
Andrei Alexandrescu wrote:
 grauzone wrote:
 Simen Kjaeraas wrote:
 Do note that I might have misinterpreted it all, as Andrei's code 
 would not do what I have outlined above, I only feel it makes the 
 most sense.
Yeah OK, but what about virtual functions? Not having it virtual is a real disadvantage, because subclass-parts aren't automatically dumped.
Streaming out is a virtual function that takes a classic interface object. (I explained that in two posts.)
There were a lot of posts in this thread. From what I've gathered, what you said wasn't really concrete. Not as concrete as the sink proposals.
 What exactly is R, and why is it simpler than a Sink delegate? A Sink 
 delegate is as simple as it gets, and what else than a string do you 
 want to output? (Hint: this is probably not supposed to be a 
 serialization framework.)
It is simpler than a Sink delegate because the delegate is not simple; it's simplistic. You can't use std.algorithm with a delegate, it only accepts one type (meaning it is very inefficient if you have multiple types to output) - it's essentially a non-design.
At some point, you need to format it to a string anyway. And it's probably not favorable to move that code into some deeply buried library code, because then you don't have full control over formatting. Anyway, I don't quite understand what you want to do. We were talking abou improving toString, right?
 One thing that I could imagine that put() automatically takes care of 
 formatting various data types into a string. Okay, where can I pass 
 format specifiers? What if put() can't deal with the type? Or does it 
 call std.string.format() anyway? Then why the indirection through the 
 string? Why not call format() directly? (Yes, format() needs to be 
 able to output using a sink instead of returning a string.)
I'd spend more time on explaining that but I fear you want more to convince yourself and others that output streams are no good and that your non-design is simpler, than actually getting answers to your questions.
It's not my design, and I didn't even come up with that proposal. Come on, I know my tone and my posts is bitchy as hell, but flaming is not really what I'm up to.
 Oh by the way, unlike a weird template, sink works with virtual 
 methods, too.

 I have the impression Andrei wants to cast everything into ranges 
 instead of adhering to KISS.
I want to adhere to KISS, and therefore I want to support output ranges with e.g. strings and files. If you don't take the time to look at ranges as you yourself said, then why do you spend time commenting on them? Shouldn't things go the other way?
Oh, I look at the Phobos docs as it seems necessary. But I still might not know to the fullest how the pieces fit together and so on.
 
 Andrei
Apr 24 2009
prev sibling parent Christopher Wright <dhasenan gmail.com> writes:
Andrei Alexandrescu wrote:
 grauzone wrote:
 Simen Kjaeraas wrote:
 Do note that I might have misinterpreted it all, as Andrei's code 
 would not do what I have outlined above, I only feel it makes the 
 most sense.
Yeah OK, but what about virtual functions? Not having it virtual is a real disadvantage, because subclass-parts aren't automatically dumped.
Streaming out is a virtual function that takes a classic interface object. (I explained that in two posts.)
 What exactly is R, and why is it simpler than a Sink delegate? A Sink 
 delegate is as simple as it gets, and what else than a string do you 
 want to output? (Hint: this is probably not supposed to be a 
 serialization framework.)
It is simpler than a Sink delegate because the delegate is not simple; it's simplistic. You can't use std.algorithm with a delegate, it only accepts one type (meaning it is very inefficient if you have multiple types to output) - it's essentially a non-design.
There are two possible use cases: serializing (to a text-based or binary format) and formatting. Serializing won't always fit here. For example, if you want to serialize to XML, you need to tell the serializer when you're beginning a tag and what to name it and when to end it. This might be possible with ranges, but it would be awkward. Or maybe you have different concerns when serializing in one binary format versus another. Or you're outputting JSON, and you could view something as an array of objects or as a single object -- you need to specify that. Formatting is the other concern. This is a special case of non-hierarchical serialization, for which ranges could work. However, formatting *has* to be general. I rarely need to override a formatting method, but I often need to access something via an interface or base class and format it. If this does not work, then toString is vastly superior. And to gain the benefits you're talking about, I have to be able to pass in different output streams. You can get the first requirement by having a method that takes a formatting struct on Object, but then object.d depends on formatting -- this isn't a reasonable situation. object.d can at most define an interface for a formatting method: interface OutStream { ... } class Object { ... void print (string format, OutStream stream); } This is still pushing it. An alternative is to have: void Object.print (void delegate (...) sink);
Apr 24 2009
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Apr 23 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Apr 23 2009
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 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 ...); }
I see now, yes I agree (I think that was don's original request anyways). That interface has to go in the runtime, though. We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString. This means struct interfaces are a requirement if you want to use ranges :( -Steve
Apr 23 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Steven Schveighoffer wrote:
 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 ...); }
I see now, yes I agree (I think that was don's original request anyways). That interface has to go in the runtime, though. We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString. This means struct interfaces are a requirement if you want to use ranges :(
We're in good shape actually. OutRange as a dynamic interface and an implicit interface using .put against a struct will work just as well with templates. (The template doesn't care whether obj.put(x) is a virtual call or statically-bound call.) Andrei
Apr 23 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Andrei Alexandrescu wrote:
 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 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 ...); }
I see now, yes I agree (I think that was don's original request anyways). That interface has to go in the runtime, though. We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString. This means struct interfaces are a requirement if you want to use ranges :(
We're in good shape actually. OutRange as a dynamic interface and an implicit interface using .put against a struct will work just as well with templates. (The template doesn't care whether obj.put(x) is a virtual call or statically-bound call.) Andrei
"We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString." Note that toString is a virtual method. You are proposing replacing toString with a template. You cannot have virtual template methods. Ergo, "new toString" would be inaccessible without the actual type, and certainly not at runtime. -- Daniel
Apr 23 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Daniel Keep wrote:
 
 Andrei Alexandrescu wrote:
 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 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 ...); }
I see now, yes I agree (I think that was don's original request anyways). That interface has to go in the runtime, though. We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString. This means struct interfaces are a requirement if you want to use ranges :(
We're in good shape actually. OutRange as a dynamic interface and an implicit interface using .put against a struct will work just as well with templates. (The template doesn't care whether obj.put(x) is a virtual call or statically-bound call.) Andrei
"We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString." Note that toString is a virtual method. You are proposing replacing toString with a template. You cannot have virtual template methods. Ergo, "new toString" would be inaccessible without the actual type, and certainly not at runtime.
The toStream that I have in mind is virtual and takes an interface of type OutRange as outlined above. Andrei
Apr 23 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Apr 2009 10:30:15 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Daniel Keep wrote:
  Andrei Alexandrescu wrote:
 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 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 ...); }
I see now, yes I agree (I think that was don's original request anyways). That interface has to go in the runtime, though. We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString. This means struct interfaces are a requirement if you want to use ranges :(
We're in good shape actually. OutRange as a dynamic interface and an implicit interface using .put against a struct will work just as well with templates. (The template doesn't care whether obj.put(x) is a virtual call or statically-bound call.) Andrei
"We may not be able to do this using templates... it has to be a virtual function in Object to be on-par with toString." Note that toString is a virtual method. You are proposing replacing toString with a template. You cannot have virtual template methods. Ergo, "new toString" would be inaccessible without the actual type, and certainly not at runtime.
The toStream that I have in mind is virtual and takes an interface of type OutRange as outlined above.
OK, that's fine, I was working off your original proposal: void streamOut(R)(R range) { foreach(x; a) range.put(x); range.put(b); range.put(c); } Of course, this then eliminates structs from being OutRange's without having struct interfaces. As most ranges are structs (and rightfully so, who wants to call 3 virtual functions every loop!), they would have to be wrapped under the current compiler. Or am I missing something else? -Steve
Apr 23 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
   As most ranges are structs (and rightfully
 so, who wants to call 3 virtual functions every loop!), they would have 
 to be wrapped under the current compiler. Or am I missing something else?
Yes, some wrapping would have to be done. Hopefully it will simple enough to keep things appealingly easy: obj.toString(dynaRange(range)); Andrei
Apr 23 2009
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Andrei Alexandrescu wrote:
 Steven Schveighoffer wrote:
 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 ...); }
What exactly is the problem with requiring the input to the sink to be a string (or actually const(char)[])? Requiring an overload for every basic type + Object would be quite cumbersome if you had to do it every time you want to send the output somewhere else. Also, it wouldn't work for structs and unions... (Unless you plan to implement a default OutRange that converts everything it gets to strings and passes it on?)
Apr 23 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Frits van Bommel wrote:
 Andrei Alexandrescu wrote:
 Steven Schveighoffer wrote:
 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 ...); }
What exactly is the problem with requiring the input to the sink to be a string (or actually const(char)[])?
You'd be forced to use intermediate strings for everything. I guess it's not a huge concern.
 Requiring an overload for every basic type + Object would be quite 
 cumbersome if you had to do it every time you want to send the output 
 somewhere else. Also, it wouldn't work for structs and unions...
 (Unless you plan to implement a default OutRange that converts 
 everything it gets to strings and passes it on?)
I'm thinking of only allowing a few fundamental types and then have user code build the rest using them. Andrei
Apr 23 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Andrei Alexandrescu 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);
 }
// object.d class Object { void streamOut(R)(R range); } No?
Apr 23 2009
parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Apr 23, 2009 at 6:01 PM, Christopher Wright <dhasenan gmail.com> wr=
ote:
 Andrei Alexandrescu 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)
 {
 =A0 =A0foreach(x; a) range.put(x);
 =A0 =A0range.put(b);
 =A0 =A0range.put(c);
 }
// object.d class Object { =A0 =A0 =A0 =A0void streamOut(R)(R range); } No?
No. Templated methods are not virtual.
Apr 23 2009
prev sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent. Second, since we have cool stuff in D, like templates, boxing, and other advanced things, then compared to them, it should not be a big deal to have automatic creation of toString for structs and objects. (This could even be on-demand, i.e. unless called, the toString is not created for an object/struct.) Since the purpose of toString here is not Grand Style, it should suffice to just recursively print the struct with its possible substructs, etc. This would relieve the programmer from the entire extra work, and it would also make objects look tidyer in source code. Actually, this way, it would become trivial to print stuff: myFancyStructWithInnerStructs st; myRealCoolObject mo; int i; float f; string s; writeln(st,mo,i,f,s); Here the programmer couldn't care less about looks and formatting, *as long as* the output is legible and clear. And what luxury -- not having to update the toString function each time you change the class' structure! (That's a relief in the early stages of the program, when everything is alive and fluid, before one settles on the optimum structure.) Naturally, if the programmer *does* supply a toString() method, then that'd be used instead. -------- Another way to do this would be to have a template function that writeln (but not writefln) calls, which introspects the printee, and prints it.
Apr 23 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Georg Wrede wrote:
 Second, since we have cool stuff in D, like templates, boxing, and other 
 advanced things, then compared to them, it should not be a big deal to 
 have automatic creation of toString for structs and objects. (This could 
 even be on-demand, i.e. unless called, the toString is not created for 
 an object/struct.)
 
 Since the purpose of toString here is not Grand Style, it should suffice 
 to just recursively print the struct with its possible substructs, etc.
 
 This would relieve the programmer from the entire extra work, and it 
 would also make objects look tidyer in source code.
Did you know that this: import std.conv, std.stdio; struct S1 { int a = 42; S2 b; } struct S2 { int x = 4; float y = 5.5; } void main() { writeln(to!string(S1())); } prints this S1(42, S2(4, 5.5)) ? Andrei
Apr 23 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Andrei Alexandrescu wrote:
 Georg Wrede wrote:
 Second, since we have cool stuff in D, like templates, boxing, and 
 other advanced things, then compared to them, it should not be a big 
 deal to have automatic creation of toString for structs and objects. 
 (This could even be on-demand, i.e. unless called, the toString is not 
 created for an object/struct.)

 Since the purpose of toString here is not Grand Style, it should 
 suffice to just recursively print the struct with its possible 
 substructs, etc.

 This would relieve the programmer from the entire extra work, and it 
 would also make objects look tidyer in source code.
Did you know that this: import std.conv, std.stdio; struct S1 { int a = 42; S2 b; } struct S2 { int x = 4; float y = 5.5; } void main() { writeln(to!string(S1())); } prints this S1(42, S2(4, 5.5))
Wow! What if writeln would automatically call to!string for any object or struct?
Apr 23 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Georg Wrede wrote:
 Wow!
 
 What if writeln would automatically call to!string for any object or 
 struct?
That's the plan, I didn't get around to it. I want to do it the right way, i.e. with general streams, not strings. Andrei
Apr 23 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
Andrei Alexandrescu wrote:
 Georg Wrede wrote:
 Wow!

 What if writeln would automatically call to!string for any object or 
 struct?
That's the plan, I didn't get around to it. I want to do it the right way, i.e. with general streams, not strings.
I'm just impressed.
Apr 23 2009
prev sibling parent reply Don <nospam nospam.com> writes:
Georg Wrede wrote:
 Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out? BTW to everyone, 'Sink' was not a proposal. I was just saying that almost anything's better than the current toString().
Apr 23 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Don wrote:
 Georg Wrede wrote:
 Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you? They're not stored as strings (not Janice's anyway), but I don't understand the question.
 BTW to everyone, 'Sink' was not a proposal. I was just saying that 
 almost anything's better than the current toString().
Apr 23 2009
parent reply Don <nospam nospam.com> writes:
Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you? They're not stored as strings (not Janice's anyway), but I don't understand the question.
You can write: int a, b; a=10; b=20; writefln("%d %x", a, b); I'd like to be able to write: BigInt a, b; a=10; b=20; writefln("%d %x", a, b); and have it behave exactly the same.
 
 BTW to everyone, 'Sink' was not a proposal. I was just saying that 
 almost anything's better than the current toString().
Apr 23 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Don wrote:
 Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you? They're not stored as strings (not Janice's anyway), but I don't understand the question.
You can write: int a, b; a=10; b=20; writefln("%d %x", a, b); I'd like to be able to write: BigInt a, b; a=10; b=20; writefln("%d %x", a, b); and have it behave exactly the same.
Hmm. My idea was to only have writeln (and not writefln) be automated. (For the small/debugging purpose.) Andrei seems to be at this, but right now I don't know enough details to say anything. It seems to be an even bigger thing than what I suggested, and knowing he does things in a universal way, one would assume that if a class "wants" to be printed in some way, then maybe there'll be some provisions for it. But, things like BigInt, that really are classes or structs that have to be printed in a specific way, I have a hard time figuring out how to printe them using write_f_ln. One way would be to have the format specification (as in "%x") be somehow passed to the toString of the struct/class. Then the class could decide for itself how to be printed in this case. But even this is stretching it a bit, since some more complicated class/struct might need a more elaborate hint than just one letter. And by that time the whole thing starts to crumble, in usability issues, at least. One thing we sholuld be wary of is overdesign. BigInt is ok, but by the time we try to include a class called CompleteSimulationOfAnF1RaceCar, we're screwed. :-) I see no way to incorporate them into writefln or even plain writeln. Or at least, no *use*.
Apr 23 2009
parent reply Don <nospam nospam.com> writes:
Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you? They're not stored as strings (not Janice's anyway), but I don't understand the question.
You can write: int a, b; a=10; b=20; writefln("%d %x", a, b); I'd like to be able to write: BigInt a, b; a=10; b=20; writefln("%d %x", a, b); and have it behave exactly the same.
Hmm. My idea was to only have writeln (and not writefln) be automated. (For the small/debugging purpose.) Andrei seems to be at this, but right now I don't know enough details to say anything. It seems to be an even bigger thing than what I suggested, and knowing he does things in a universal way, one would assume that if a class "wants" to be printed in some way, then maybe there'll be some provisions for it. But, things like BigInt, that really are classes or structs that have to be printed in a specific way, I have a hard time figuring out how to printe them using write_f_ln. One way would be to have the format specification (as in "%x") be somehow passed to the toString of the struct/class. Then the class could decide for itself how to be printed in this case. But even this is stretching it a bit, since some more complicated class/struct might need a more elaborate hint than just one letter. And by that time the whole thing starts to crumble, in usability issues, at least. One thing we sholuld be wary of is overdesign. BigInt is ok, but by the time we try to include a class called CompleteSimulationOfAnF1RaceCar, we're screwed. :-) I see no way to incorporate them into writefln or even plain writeln. Or at least, no *use*.
I think it'd be reasonable to limit things to the options available for built-in types. Outside of that, custom formatting functions make a lot of sense. The problem is that toString() _looks_ like it emulates built-in formatting, but it only does '%s'. So it's really beguiling. BTW, when passing the output to a sink, it should be possible to (say) format your members with '%x' format, but you can't do that by permanently altering sink: it should revert to its previous value once you've sunk your last member. (I think this C++ iostreams got this wrong).
Apr 23 2009
next sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Don wrote:
 Georg Wrede wrote:
 One thing we sholuld be wary of is overdesign. BigInt is ok, but by 
 the time we try to include a class called 
 CompleteSimulationOfAnF1RaceCar, we're screwed. :-)  I see no way to 
 incorporate them into writefln or even plain writeln. Or at least, no 
 *use*.
I think it'd be reasonable to limit things to the options available for built-in types. Outside of that, custom formatting functions make a lot of sense. The problem is that toString() _looks_ like it emulates built-in formatting, but it only does '%s'. So it's really beguiling.
Heh, one thought is, suppose we could have arbitrary format specifications in writef. Say, if we wrote %&lkjasdf; this string would be passed to toString. (It would of course be up to the class to error-check the string, writefln obviously cant (or shouldn't) do it.) So, things are doable. But I'm really not looking forward to that kind of sports. Any elaborate printing or formatting should be handled outside writefln &co.
 BTW, when passing the output to a sink, it should be possible to (say) 
 format your members with '%x' format, but you can't do that by 
 permanently altering sink: it should revert to its previous value once 
 you've sunk your last member. (I think this C++ iostreams got this wrong).
I guess they, too, thought of making it "easier" in the wrong place. Just because you can, doesn't mean you have to. (OT: an excellent example of this It's Done Because We Noticed We Could stuff is in Firefox. When a picture is a link to another page, and you want to drag that to the tab area, the entire picture is dragged with the mouse. Now, how the hell am I supposed to hit the small tab area when the large picture covers half of my Firefox?? So now I have to learn to remember to grab bigger pictures near some edge. And I really can't see *any* valid benefit for having to drag the picture. I'd rather have it the old way, where the mouse pointer simply changes shape, so you know you're dragging. Damn, damn...)
Apr 23 2009
next sibling parent "Joel C. Salomon" <joelcsalomon gmail.com> writes:
Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 One thing we sholuld be wary of is overdesign. BigInt is ok, but by
 the time we try to include a class called
 CompleteSimulationOfAnF1RaceCar, we're screwed. :-)  I see no way to
 incorporate them into writefln or even plain writeln. Or at least, no
 *use*.
I think it'd be reasonable to limit things to the options available for built-in types. Outside of that, custom formatting functions make a lot of sense. The problem is that toString() _looks_ like it emulates built-in formatting, but it only does '%s'. So it's really beguiling.
Heh, one thought is, suppose we could have arbitrary format specifications in writef. Say, if we wrote %&lkjasdf; this string would be passed to toString. (It would of course be up to the class to error-check the string, writefln obviously cant (or shouldn't) do it.) So, things are doable. But I'm really not looking forward to that kind of sports. Any elaborate printing or formatting should be handled outside writefln &co.
Take a look at the formatting library for Plan 9. It’s very much like printf & co., except it exposes enough of its internals to allow for new formats to be added in. See the documentation (for the *nix-ported version) at <http://swtch.com/plan9port/man/man3/print.html> and <http://swtch.com/plan9port/man/man3/fmtinstall.html>. For example: typedef struct { double r, i; } Complex; #pragma varargck type "X" Complex // compiler checks type-safety int Xfmt(Fmt *f) { Complex c; c = va_arg(f−>args, Complex); return fmtprint(f, "(%g,%g)", c.r, c.i); // can use flags here } main(...) { Complex x = (Complex){ 1.5, −2.3 }; fmtinstall('X', Xfmt); print("x = %X\n", x); } With D’s type-safe variadic functions, this model can be made really powerful. —Joel Salomon
Apr 23 2009
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi> wrote:

 (OT: an excellent example of this It's Done Because We Noticed We Could  
 stuff is in Firefox. When a picture is a link to another page, and you  
 want to drag that to the tab area, the entire picture is dragged with  
 the mouse. Now, how the hell am I supposed to hit the small tab area  
 when the large picture covers half of my Firefox??

 So now I have to learn to remember to grab bigger pictures near some  
 edge. And I really can't see *any* valid benefit for having to drag the  
 picture. I'd rather have it the old way, where the mouse pointer simply  
 changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image, so I can still see where my mouse pointer is aimed. Maybe you don't have enough colors enabled on your screen? -Steve
Apr 23 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
 
 (OT: an excellent example of this It's Done Because We Noticed We 
 Could stuff is in Firefox. When a picture is a link to another page, 
 and you want to drag that to the tab area, the entire picture is 
 dragged with the mouse. Now, how the hell am I supposed to hit the 
 small tab area when the large picture covers half of my Firefox??

 So now I have to learn to remember to grab bigger pictures near some 
 edge. And I really can't see *any* valid benefit for having to drag 
 the picture. I'd rather have it the old way, where the mouse pointer 
 simply changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image, so I can still see where my mouse pointer is aimed. Maybe you don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the next cubicle, etc. But there should be some obvious or useful *purpose* for dragging entire pictures where a mouse pointer would be clearer, cleaner, easier for the user, and use less computer cycles. I mean, who's such a nutcase that he forgets halfway in the dragging, what it is he's dragging?
Apr 23 2009
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:

 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi>  
 wrote:

 (OT: an excellent example of this It's Done Because We Noticed We  
 Could stuff is in Firefox. When a picture is a link to another page,  
 and you want to drag that to the tab area, the entire picture is  
 dragged with the mouse. Now, how the hell am I supposed to hit the  
 small tab area when the large picture covers half of my Firefox??

 So now I have to learn to remember to grab bigger pictures near some  
 edge. And I really can't see *any* valid benefit for having to drag  
 the picture. I'd rather have it the old way, where the mouse pointer  
 simply changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image, so I can still see where my mouse pointer is aimed. Maybe you don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the next cubicle, etc. But there should be some obvious or useful *purpose* for dragging entire pictures where a mouse pointer would be clearer, cleaner, easier for the user, and use less computer cycles. I mean, who's such a nutcase that he forgets halfway in the dragging, what it is he's dragging?
It might be useful if you accidentally start dragging the wrong thing, and then realize because you are dragging the wrong picture/text/etc. But my point was really: you complained that you couldn't see the target because the picture is covering it. My experience is that I can clearly see the target because the picture is translucent (I can see the target "underneath" the picture). -Steve
Apr 23 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
 I mean, who's such a nutcase that he forgets halfway in the dragging, 
 what it is he's dragging?
It might be useful if you accidentally start dragging the wrong thing, and then realize because you are dragging the wrong picture/text/etc. But my point was really: you complained that you couldn't see the target because the picture is covering it. My experience is that I can clearly see the target because the picture is translucent (I can see the target "underneath" the picture).
My complaint was about doing stuff just because you can. The dragging was just the first gross example that crossed my mind. (I'm on a slow graphics card. Besides, it hasn't bothered me enough to start investigating. Heck, for all I know, I could configure it away.)
Apr 24 2009
parent "Nick Sabalausky" <a a.a> writes:
"Georg Wrede" <georg.wrede iki.fi> wrote in message 
news:gsrqbj$iu1$1 digitalmars.com...
 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> 
 wrote:
 I mean, who's such a nutcase that he forgets halfway in the dragging, 
 what it is he's dragging?
It might be useful if you accidentally start dragging the wrong thing, and then realize because you are dragging the wrong picture/text/etc. But my point was really: you complained that you couldn't see the target because the picture is covering it. My experience is that I can clearly see the target because the picture is translucent (I can see the target "underneath" the picture).
My complaint was about doing stuff just because you can. The dragging was just the first gross example that crossed my mind. (I'm on a slow graphics card. Besides, it hasn't bothered me enough to start investigating. Heck, for all I know, I could configure it away.)
When I try to drag a group of files in Windows Explorer it makes them translucent instead of opaque. But I *still* find it unforgivably difficult to see underneath to where I'm dropping them. (Although maybe I can turn that off...)
Apr 24 2009
prev sibling next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Apr 23, 2009 at 2:32 PM, Georg Wrede <georg.wrede iki.fi> wrote:

 (OT: an excellent example of this It's Done Because We Noticed We Could
 stuff is in Firefox. When a picture is a link to another page, and you want
 to drag that to the tab area, the entire picture is dragged with the mouse.
 Now, how the hell am I supposed to hit the small tab area when the large
 picture covers half of my Firefox??
Sure it looks good, and the computer owner can brag to the guy in the next cubicle, etc. But there should be some obvious or useful *purpose* for dragging entire pictures where a mouse pointer would be clearer, cleaner, easier for the user, and use less computer cycles. I mean, who's such a nutcase that he forgets halfway in the dragging, what it is he's dragging?
Middle-click.
Apr 23 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Jarrett Billingsley wrote:
 On Thu, Apr 23, 2009 at 2:32 PM, Georg Wrede <georg.wrede iki.fi> wrote:
 
 (OT: an excellent example of this It's Done Because We Noticed We Could
 stuff is in Firefox. When a picture is a link to another page, and you want
 to drag that to the tab area, the entire picture is dragged with the mouse.
 Now, how the hell am I supposed to hit the small tab area when the large
 picture covers half of my Firefox??
Sure it looks good, and the computer owner can brag to the guy in the next cubicle, etc. But there should be some obvious or useful *purpose* for dragging entire pictures where a mouse pointer would be clearer, cleaner, easier for the user, and use less computer cycles. I mean, who's such a nutcase that he forgets halfway in the dragging, what it is he's dragging?
Middle-click.
Yeah. But I still don't see the glamouros advantages in dragging whole pictures. And I often drag stuff to existing tabs. A good example is when browsing http://apod.nasa.gov/apod/ap090424.html where I usually end up with a dozen tabs in no time.
Apr 24 2009
parent Benji Smith <dlanguage benjismith.net> writes:
Georg Wrede wrote:
 Jarrett Billingsley wrote:
 I mean, who's such a nutcase that he forgets halfway in the dragging, 
 what
 it is he's dragging?
Middle-click.
Yeah. But I still don't see the glamouros advantages in dragging whole pictures. And I often drag stuff to existing tabs. A good example is when browsing http://apod.nasa.gov/apod/ap090424.html where I usually end up with a dozen tabs in no time.
I think it's because Firefox doesn't know you're just dragging those images to a tab. For all the browser knows, you're playing a game of chess, and you're dragging a pawn to E5. In which case, it makes a lot of sense for a ghost image to follow the drag behavior. For generalized dragdrop, I think ghosted images are a good, safe guess. Did you know you can right-click to "Open in New Tab"? --benji
Apr 27 2009
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:

 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi>  
 wrote:

 (OT: an excellent example of this It's Done Because We Noticed We  
 Could stuff is in Firefox. When a picture is a link to another page,  
 and you want to drag that to the tab area, the entire picture is  
 dragged with the mouse. Now, how the hell am I supposed to hit the  
 small tab area when the large picture covers half of my Firefox??

 So now I have to learn to remember to grab bigger pictures near some  
 edge. And I really can't see *any* valid benefit for having to drag  
 the picture. I'd rather have it the old way, where the mouse pointer  
 simply changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image, so I can still see where my mouse pointer is aimed. Maybe you don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the next cubicle, etc. But there should be some obvious or useful *purpose* for dragging entire pictures where a mouse pointer would be clearer, cleaner, easier for the user, and use less computer cycles. I mean, who's such a nutcase that he forgets halfway in the dragging, what it is he's dragging?
One thing that does annoy me is if you are doing this over a slow RDP link, the eye candy isn't worth it. I was never a huge fan of application themes. I don't mind a theme for the whole system (as long as it's simple), but I don't want iTunes to look different just because it can. I think it has been discussed before that most video editors have the slickest GUI, with real-looking knobs and "led's", but the video editing part of it is buggy as hell. -Steve
Apr 23 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:op.usux6bskeav7ka steves.networkengines.com...
 I was never a huge fan of application themes.  I don't mind a theme for 
 the whole system (as long as it's simple), but I don't want iTunes to look 
 different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do the subject justice without delving into a giant pile of expletives. But worse still is when they decide to go and piss all over not just standard looks, but also standard behaviors. Like how the Win build of iTunes will still ignore/"eat" any click that brings it to the foreground. If I wanted that behavior I'd be running a Mac. The absolute worst of all though is when an app (*cough* skype *cough*) decides that "close" and "the 'close' button" should mean "don't close anything at all, but minimize to tray instead". That should be a firing squad offense ;) Joking aside though, any of these are guaranteed ways to make me lose any and all respect for a piece of software and its developers, especially if they're arrogant enough to provide no way to turn such things off.
Apr 23 2009
next sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
 news:op.usux6bskeav7ka steves.networkengines.com...
 I was never a huge fan of application themes.  I don't mind a theme for 
 the whole system (as long as it's simple), but I don't want iTunes to look 
 different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do the subject justice without delving into a giant pile of expletives. But worse still is when they decide to go and piss all over not just standard looks, but also standard behaviors. Like how the Win build of iTunes will still ignore/"eat" any click that brings it to the foreground. If I wanted that behavior I'd be running a Mac. The absolute worst of all though is when an app (*cough* skype *cough*) decides that "close" and "the 'close' button" should mean "don't close anything at all, but minimize to tray instead". That should be a firing squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty much expect it of any application that's meant to be running for a long time and only rarely needing user interaction (such as a bittorrent client).
Apr 23 2009
next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Thu, 23 Apr 2009 21:40:36 -0400, Christopher Wright wrote:

 Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.usux6bskeav7ka steves.networkengines.com...
 I was never a huge fan of application themes.  I don't mind a theme
 for the whole system (as long as it's simple), but I don't want iTunes
 to look different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do the subject justice without delving into a giant pile of expletives. But worse still is when they decide to go and piss all over not just standard looks, but also standard behaviors. Like how the Win build of iTunes will still ignore/"eat" any click that brings it to the foreground. If I wanted that behavior I'd be running a Mac. The absolute worst of all though is when an app (*cough* skype *cough*) decides that "close" and "the 'close' button" should mean "don't close anything at all, but minimize to tray instead". That should be a firing squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty much expect it of any application that's meant to be running for a long time and only rarely needing user interaction (such as a bittorrent client).
I think he was referring to not having an exit. That is File->Exit is also minimize to tray which is not the case in most such apps.
Apr 23 2009
prev sibling parent reply BCS <none anon.com> writes:
Hello Christopher,

 Nick Sabalausky wrote:
  
 The absolute worst of all though is when an app (*cough* skype
 *cough*) decides that "close" and "the 'close' button" should mean
 "don't close anything at all, but minimize to tray instead". That
 should be a firing squad offense ;)
 
I'd be killing my IM client constantly if not for that feature. I pretty much expect it of any application that's meant to be running for a long time and only rarely needing user interaction (such as a bittorrent client).
yah, for some programs you rarely want to close the program but often want to close the UI.
Apr 23 2009
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
BCS wrote:
 Hello Christopher,
 
 Nick Sabalausky wrote:
  
 The absolute worst of all though is when an app (*cough* skype
 *cough*) decides that "close" and "the 'close' button" should mean
 "don't close anything at all, but minimize to tray instead". That
 should be a firing squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty much expect it of any application that's meant to be running for a long time and only rarely needing user interaction (such as a bittorrent client).
yah, for some programs you rarely want to close the program but often want to close the UI.
This is one place where I think Mac OS X gets it right. It's a massive pain to close the last document open in OpenOffice.org before opening a new one, only to realise that now you have to sit through the loading screen again. -- Daniel
Apr 23 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff50558cb92691721562e news.digitalmars.com...
 Hello Christopher,

 Nick Sabalausky wrote:

 The absolute worst of all though is when an app (*cough* skype
 *cough*) decides that "close" and "the 'close' button" should mean
 "don't close anything at all, but minimize to tray instead". That
 should be a firing squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty much expect it of any application that's meant to be running for a long time and only rarely needing user interaction (such as a bittorrent client).
yah, for some programs you rarely want to close the program but often want to close the UI.
That's called "Minimize".
Apr 24 2009
next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Fri, 24 Apr 2009 13:54:26 +0400, Nick Sabalausky <a a.a> wrote:

 "BCS" <none anon.com> wrote in message
 news:a6268ff50558cb92691721562e news.digitalmars.com...
 Hello Christopher,

 Nick Sabalausky wrote:

 The absolute worst of all though is when an app (*cough* skype
 *cough*) decides that "close" and "the 'close' button" should mean
 "don't close anything at all, but minimize to tray instead". That
 should be a firing squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty much expect it of any application that's meant to be running for a long time and only rarely needing user interaction (such as a bittorrent client).
yah, for some programs you rarely want to close the program but often want to close the UI.
That's called "Minimize".
"Minimize" button usually minimizes the window to task bar. Some applications provide an additional button alongside minimize and close that minimizes to tray (Emule and others). Some other applications minimize to tray when you hold Shift while clicking the minimize button - Vypress chat, Download Master, Total Commander (plugin) and others. But overall - it's very inconsistent. I personally wish that more programs adopt Shift+Minimize -> Tray behavior, it's easy to remember and easy to implement.
Apr 24 2009
prev sibling parent reply BCS <none anon.com> writes:
Hello Nick,

 "BCS" <none anon.com> wrote in message
 news:a6268ff50558cb92691721562e news.digitalmars.com...
 
 yah, for some programs you rarely want to close the program but often
 want to close the UI.
 
That's called "Minimize".
It can be, OTOH I might want the UI process killed without killing the main program. Another point is the other side of the assertion, "you rarely want to close the program" as in 90% of the time even when I hit the x button, I don't actually want to close the program.
Apr 24 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff50d58cb92d952e5b612 news.digitalmars.com...
 Hello Nick,

 "BCS" <none anon.com> wrote in message
 news:a6268ff50558cb92691721562e news.digitalmars.com...

 yah, for some programs you rarely want to close the program but often
 want to close the UI.
That's called "Minimize".
It can be, OTOH I might want the UI process killed without killing the main program. Another point is the other side of the assertion, "you rarely want to close the program" as in 90% of the time even when I hit the x button, I don't actually want to close the program.
The whole point of the 'x' button is the close the program. Always has been. If I didn't want to close the program, I wouldn't push it. If you want to hide/kill the UI without closing the program, that's "minimize". True, minimizing to the taskbar doesn't kill the UI process/thread (assuming it even is a separate process/thread), but in the rare cases where the distinction of "UI process running/killed" actually matters, the program can still do that through a minimize to tray. And while neither "minimize" nor "close" truly mean "minimize to tray", clearly "minimize" is FAR closer in both wording and behavior. Any way you look at it, having a "close" button that doesn't "close" the app is like having a "cancel" button that prints, or a "save" button that plays music.
Apr 24 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Nick,

 "BCS" <none anon.com> wrote in message
 news:a6268ff50d58cb92d952e5b612 news.digitalmars.com...
 
 Hello Nick,
 
 "BCS" <none anon.com> wrote in message
 news:a6268ff50558cb92691721562e news.digitalmars.com...
 yah, for some programs you rarely want to close the program but
 often want to close the UI.
 
That's called "Minimize".
It can be, OTOH I might want the UI process killed without killing the main program. Another point is the other side of the assertion, "you rarely want to close the program" as in 90% of the time even when I hit the x button, I don't actually want to close the program.
The whole point of the 'x' button is the close the program. Always has been. If I didn't want to close the program, I wouldn't push it.
Are you saying you never make mistakes? There are program out there that 90% of the time when I hit the x button it was a mistake and in that cases I think it to be a good design to work around it. I guess if you really hate having it not kill the app then the program could just not /have/ a x button.
 If you want to hide/kill the UI without closing the program, that's
 "minimize". True, minimizing to the taskbar doesn't kill the UI
 process/thread (assuming it even is a separate process/thread), but in
 the rare cases where the distinction of "UI process running/killed"
 actually matters, the program can still do that through a minimize to
 tray. And while neither "minimize" nor "close" truly mean "minimize to
 tray", clearly "minimize" is FAR closer in both wording and behavior.
 Any way you look at it, having a "close" button that doesn't "close"
 the app is like having a "cancel" button that prints, or a "save"
 button that plays music.
 
Your missing my point. I don't want to re-task the button but make it not do something that most of the time is not what I want.
Apr 24 2009
next sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
BCS wrote:
 I guess if you 
 really hate having it not kill the app then the program could just not 
 /have/ a x button.
Your window manager does not support such windows.
Apr 24 2009
parent BCS <ao pathlink.com> writes:
Reply to Christopher,

 BCS wrote:
 
 I guess if you really hate having it not kill the app then the
 program could just not /have/ a x button.
 
Your window manager does not support such windows.
So I guess we're stuck with the no-close close button if we don't want any way to close the app in a single click.
Apr 24 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <ao pathlink.com> wrote in message 
news:78ccfa2d3ebc18cb92e7b8abed64 news.digitalmars.com...
 Are you saying you never make mistakes? There are program out there that 
 90% of the time when I hit the x button it was a mistake and in that cases 
 I think it to be a good design to work around it.
?? Not only can I honestly say I've never had that problem, but I find the whole idea of it very strange. Are you certain that your mouse or window manager isn't just acting up?
 I guess if you really hate having it not kill the app then the program 
 could just not /have/ a x button.
You've got to be kidding me, that would be just as bad. Why would I want to have a program get rid of the standard "exit" mechanism? Whever I come across an app like that, the first thing I do is open the task manager and kill it, and then immediately uninstall it.
 Your missing my point. I don't want to re-task the button but make it not 
 do something that most of the time is not what I want.
In this particular case, that's exactly the same thing. It's the "close"/"exit" button. If it doesn't "close"/"exit" then it's been re-tasked. Either to "minimize to tray" or to "noop" or whatever.
Apr 24 2009
parent BCS <none anon.com> writes:
Hello Nick,

 I guess if you really hate having it not kill the app then the
 program could just not /have/ a x button.
 
You've got to be kidding me, that would be just as bad. Why would I want to have a program get rid of the standard "exit" mechanism?
If you basicly never want to exit it? (see below)
 Whever I come across an app like that, the first thing I do is open
 the task manager and kill it, and then immediately uninstall it.
I'll grant there are only very few cases where I want it, but in those cases I wouldn't have the program at all unless I wanted it running *all the time*. If I found myself killing/restarting the program more than rarely, I'd git rid of it and find one I don't have to do that with. For those apps, I basically never want to actually close them (even less often than I reboot) and on the few occasions when I do, I'm willing to do file->exit->"Yes I really do" sequence. As an example of a program that works this way that I'll bet you don't mind: The volume control in the system tray. I'm not even sure if there /is/ a way to close it all the way. To put it objectively: say the program take 10 sec to reload and 90% of the time (I'd bet that's low) that I click the x button, it was a mistake (bad mouse control, reflex "go way action", whatever). From that it can take 90 seconds to close the program before tuning off the x button is a net loss (as long as it's easy to figure out how to really kill it). We may have to agree to disagree; I use a few programs where having the x button kill them would be a bad thing IMHO. You disagreeing really doesn't matter to me.
Apr 25 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 24 Apr 2009 14:00:19 -0400, Nick Sabalausky <a a.a> wrote:

 "BCS" <none anon.com> wrote in message
 news:a6268ff50d58cb92d952e5b612 news.digitalmars.com...
 Hello Nick,

 "BCS" <none anon.com> wrote in message
 news:a6268ff50558cb92691721562e news.digitalmars.com...

 yah, for some programs you rarely want to close the program but often
 want to close the UI.
That's called "Minimize".
It can be, OTOH I might want the UI process killed without killing the main program. Another point is the other side of the assertion, "you rarely want to close the program" as in 90% of the time even when I hit the x button, I don't actually want to close the program.
The whole point of the 'x' button is the close the program. Always has been. If I didn't want to close the program, I wouldn't push it. If you want to hide/kill the UI without closing the program, that's "minimize". True, minimizing to the taskbar doesn't kill the UI process/thread (assuming it even is a separate process/thread), but in the rare cases where the distinction of "UI process running/killed" actually matters, the program can still do that through a minimize to tray. And while neither "minimize" nor "close" truly mean "minimize to tray", clearly "minimize" is FAR closer in both wording and behavior. Any way you look at it, having a "close" button that doesn't "close" the app is like having a "cancel" button that prints, or a "save" button that plays music.
Yahoo messenger's X button behavior: click on it -> "Although the main window has been closed, Yahoo! Messenger will continue to run in the system tray..." With a checkbox that says "Show this message in the future." That's perfect for me. YM also has an option to automatically remove the taskbar button when minimized (so minimized does the behavior you want it to do). -Steve
Apr 24 2009
prev sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
 news:op.usux6bskeav7ka steves.networkengines.com...
 I was never a huge fan of application themes.  I don't mind a theme for 
 the whole system (as long as it's simple), but I don't want iTunes to look 
 different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do the subject justice without delving into a giant pile of expletives.
It took me some serious browsing before I found a non-obtrusive skin for gmplayer. And I hated to have to do that. It should have been the default.
 But worse still is when they decide to go and piss all over not just standard 
 looks, but also standard behaviors. Like how the Win build of iTunes will 
 still ignore/"eat" any click that brings it to the foreground. If I wanted 
 that behavior I'd be running a Mac.
That's a good thing with many *nix GUIs. You can have several overlapping windows, and even do stuff in the non-top ones. But they really should respect the target GUIs way of doing things, when porting.
 The absolute worst of all though is when an app (*cough* skype *cough*) 
 decides that "close" and "the 'close' button" should mean "don't close 
 anything at all, but minimize to tray instead". That should be a firing 
 squad offense ;) Joking aside though, any of these are guaranteed ways to 
 make me lose any and all respect for a piece of software and its developers, 
 especially if they're arrogant enough to provide no way to turn such things 
 off.
Yeah, the biggest motivation (next to being graphical per se) for GUIs was uniform app behavior. That way you only would need to learn the common basics, and then, ostensibly, you could use any new app right off the bat. (In the bad old days, you really had to learn to use every app, one at a time.)
Apr 24 2009
parent reply grauzone <none example.net> writes:
 It took me some serious browsing before I found a non-obtrusive skin for 
 gmplayer. And I hated to have to do that. It should have been the default.
AFAIK, the gmplayer GUI is deprecated. Use mplayer or smplayer. smplayer is a GUI for mplayer that surprisingly manages to use a standard GUI, and not some skinable specially-made media GUI bullshit, that plagues most media players.
Apr 24 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
grauzone wrote:
 It took me some serious browsing before I found a non-obtrusive skin 
 for gmplayer. And I hated to have to do that. It should have been the 
 default.
AFAIK, the gmplayer GUI is deprecated. Use mplayer or smplayer. smplayer is a GUI for mplayer that surprisingly manages to use a standard GUI, and not some skinable specially-made media GUI bullshit, that plagues most media players.
Thanks!
Apr 24 2009
prev sibling parent reply Georg Wrede <georg.wrede iki.fi> writes:
Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
 Steven Schveighoffer wrote:
 On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi> 
 So now I have to learn to remember to grab bigger pictures near some 
 edge. And I really can't see *any* valid benefit for having to drag 
 the picture. I'd rather have it the old way, where the mouse pointer 
 simply changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image, so I can still see where my mouse pointer is aimed. Maybe you don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the next cubicle, etc. But there should be some obvious or useful *purpose* for dragging entire pictures where a mouse pointer would be clearer, cleaner, easier for the user, and use less computer cycles. I mean, who's such a nutcase that he forgets halfway in the dragging, what it is he's dragging?
One thing that does annoy me is if you are doing this over a slow RDP link, the eye candy isn't worth it. I was never a huge fan of application themes. I don't mind a theme for the whole system (as long as it's simple), but I don't want iTunes to look different just because it can. I think it has been discussed before that most video editors have the slickest GUI, with real-looking knobs and "led's", but the video editing part of it is buggy as hell.
You're the first one to comment on the actual issue!!! :-) Those video editors, iTunes and such look like they're programmed by 12-year olds. Somewhere there should be an adult saying what not to do! I bet the guy who did this never expected that whole-picture dragging actually uses more electricity in your computer. When every Firefox user (and the others "who have to implement this too, so as not to look inferior!") in the whole world drags whole pictures, the combined increase in world electric usage rises well above his day-job salary. Greenpeace ought to shoot him.
Apr 24 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Georg Wrede" <georg.wrede iki.fi> wrote in message 
news:gsrrfn$kv3$1 digitalmars.com...
 Those video editors, iTunes and such look like they're programmed by 
 12-year olds. Somewhere there should be an adult saying what not to do!
Well put.
 I bet the guy who did this never expected that whole-picture dragging 
 actually uses more electricity in your computer. When every Firefox user 
 (and the others "who have to implement this too, so as not to look 
 inferior!") in the whole world drags whole pictures, the combined increase 
 in world electric usage rises well above his day-job salary.

 Greenpeace ought to shoot him.
Funny, earlier today I was just thinking very much the same thing about a video I saw a few weeks ago of Palm's WebOS (Or it might have been some clone of WebOS). Fancy moving curves and scaling icons that serve absolutely no purpose besides 1. "flash for the sake of flash" (I *hate* that!) and 2. drain the battery. Which is really sad, I used to have so much respect for Palm...But then they killed graffiti, and then replaced their PDAs with cell phones (and we never did get PDAs with hard drives, which is ridiculous, even my portable music player has a damn hard drive, which of course is one device I wouldn't even need if my PDA *had a hdd!!*), and now this WebOS garbage, sheesh...And speaking of PDAs, now Nintendo's been changing their DS from a reasonable gaming device into the world's shittiest PDA...Man, the world of software and consumer electronics really depresses me these days...
Apr 24 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
Nick Sabalausky wrote:
 "Georg Wrede" <georg.wrede iki.fi> wrote in message 
 news:gsrrfn$kv3$1 digitalmars.com...
 Those video editors, iTunes and such look like they're programmed by 
 12-year olds. Somewhere there should be an adult saying what not to do!
Well put.
 I bet the guy who did this never expected that whole-picture dragging 
 actually uses more electricity in your computer. When every Firefox user 
 (and the others "who have to implement this too, so as not to look 
 inferior!") in the whole world drags whole pictures, the combined increase 
 in world electric usage rises well above his day-job salary.

 Greenpeace ought to shoot him.
Funny, earlier today I was just thinking very much the same thing about a video I saw a few weeks ago of Palm's WebOS (Or it might have been some clone of WebOS). Fancy moving curves and scaling icons that serve absolutely no purpose besides 1. "flash for the sake of flash" (I *hate* that!) and 2. drain the battery. Which is really sad, I used to have so much respect for Palm...But then they killed graffiti, and then replaced their PDAs with cell phones (and we never did get PDAs with hard drives, which is ridiculous, even my portable music player has a damn hard drive, which of course is one device I wouldn't even need if my PDA *had a hdd!!*), and now this WebOS garbage, sheesh...And speaking of PDAs, now Nintendo's been changing their DS from a reasonable gaming device into the world's shittiest PDA...Man, the world of software and consumer electronics really depresses me these days...
It was different in the old days. In 1981 HP introduced the HP-12c financial calculator. Seems it's still sold, for about $60. I'd like to see the consumer gadget introduced this year, that is still sold in 2037. And they're built to last. I have a few HP calculators (the earliest a HP-25, I bought in 1975), and they're fiercely usable, sturdy, and definitely not cluttered with unneeded "features". I still use them, particularly the HP-28s, the HP-25, and the HP-95 (which is actually an IBM PC in palmtop size).
Apr 24 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 23 Apr 2009 19:34:38 +0400, Don <nospam nospam.com> wrote:

 Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don wrote:
 Georg Wrede wrote:
 Don 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 {
...
 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>
First of all, printing stuff "struct.toString()" style is for two things: o Debugging o Small throwaway code snippets The latter mainly being for two purposes: o Testing quick concepts, trying out library functions, etc. o For the newbie, when he's learning D, but not output formatting. No "Real Program" uses this, because there you typically do proper formatting of the output anyway, and almost never print entire structs or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you? They're not stored as strings (not Janice's anyway), but I don't understand the question.
You can write: int a, b; a=10; b=20; writefln("%d %x", a, b); I'd like to be able to write: BigInt a, b; a=10; b=20; writefln("%d %x", a, b); and have it behave exactly the same.
Hmm. My idea was to only have writeln (and not writefln) be automated. (For the small/debugging purpose.) Andrei seems to be at this, but right now I don't know enough details to say anything. It seems to be an even bigger thing than what I suggested, and knowing he does things in a universal way, one would assume that if a class "wants" to be printed in some way, then maybe there'll be some provisions for it. But, things like BigInt, that really are classes or structs that have to be printed in a specific way, I have a hard time figuring out how to printe them using write_f_ln. One way would be to have the format specification (as in "%x") be somehow passed to the toString of the struct/class. Then the class could decide for itself how to be printed in this case. But even this is stretching it a bit, since some more complicated class/struct might need a more elaborate hint than just one letter. And by that time the whole thing starts to crumble, in usability issues, at least. One thing we sholuld be wary of is overdesign. BigInt is ok, but by the time we try to include a class called CompleteSimulationOfAnF1RaceCar, we're screwed. :-) I see no way to incorporate them into writefln or even plain writeln. Or at least, no *use*.
I think it'd be reasonable to limit things to the options available for built-in types. Outside of that, custom formatting functions make a lot of sense. The problem is that toString() _looks_ like it emulates built-in formatting, but it only does '%s'. So it's really beguiling. BTW, when passing the output to a sink, it should be possible to (say) format your members with '%x' format, but you can't do that by permanently altering sink: it should revert to its previous value once you've sunk your last member. (I think this C++ iostreams got this wrong).
I'm not sure Sink should know anything about formatting. It's up to class designer to decide what custom formatters mean - they may be *very* complex. See my other post about formatting.
Apr 23 2009
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Simen Kjaeraas:
 That actually sounds like a good idea. Like you say, is has no use
 outside of debugging, but while debugging, it's quite useful.
It's also important for small script-like programs. I am using D to write a lot of them :-) Bye, bearophile
Apr 23 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 toString() is one of the most dreadful features in D.
It's also one of the most useful, and it's quite easy to understand and use. You need very little brain to use it. Features that require little/no brain are very important to me (but surely it's a quality that is at the bottom of the list of qualities for C++ programmers). Bye, bearophile
Apr 23 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
bearophile wrote:
 Don:
 toString() is one of the most dreadful features in D.
It's also one of the most useful, and it's quite easy to understand and use. You need very little brain to use it. Features that require little/no brain are very important to me (but surely it's a quality that is at the bottom of the list of qualities for C++ programmers).
Yeah! Sometimes I feel the C++ committee really thinks *every* C++ programmer is a *superhuman*. Not necessarily that he'd be overly intelligent, but *definitely* he'd have to keep 72 dozen different - best practices - gotchas - loads of things about his own code - rules, rules, rules... - exceptions to those rules - a load of other crap in his mind *every* single second he's at the keyboard. Man, I'm definitely not the one they're designing the language for. So, yes, a simple feature here, another there, so you can maybe spend a minute thinking about what you're actually trying to do with *your* code, would be welcome. Guess why I'm using D instead! PS, I don't even mind hard-to-grasp things, *as long as* they're simple and consistent to *use* for the rest of your life, after you've finished pulling your hair when learning them. :-) Proper documentation, and examples, examples and examples, really make a difference here. I find a good example saves hours of trying to read somebody's blabbering. That's another thing that I think D does right: the source is there, and *especially* I find the unit tests invaluable. That's where you see how something is supposed to be used. Like this morning I found no documentation for d_time parse(string s); I simply went to the unit tests. Got it in no time at all!
Apr 23 2009
prev sibling next sibling parent U u <u u.com> writes:
Tomas Lindquist Olsen Wrote:

 On Mon, Apr 20, 2009 at 2:47 PM, Saaa <empty needmail.com> wrote:
 Using D1 feels especially retarded today :(
Why retarded ?
I think because of new features *cough* featurism *cough*
Apr 25 2009
prev sibling parent U u <u u.com> writes:
Tomas Lindquist Olsen Wrote:

 On Mon, Apr 20, 2009 at 2:47 PM, Saaa <empty needmail.com> wrote:
 Using D1 feels especially retarded today :(
Why retarded ?
I think because of new features *cough* featurism *cough*
Apr 25 2009