www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Errors in TDPL

reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Okay. I am in no way trying to say anything negative about TDPL. In fact, 
from what I've read so far, it's absolutely fantastic and quite possibly the 
most entertaining programming book that I've read in addition to being quite 
informative about D. However, no one's perfect (Andrei included), and there 
are bound to be errors in the book which didn't get caught.

My thought was that we could point out any errors that we've found so that 
Andrei can get them fixed in future printings and/or we can find out that 
they aren't actually errors.

The only errors that I've found so far have been omissions in the list of 
keywords on page 31. I'm listing them according to my understanding of 
whether they're still keywords, since I think that some have been removed as 
keywords or at least are no longer supposed to be keywords.

Definitely should be there
--------------------------
immutable
lazy
pure
nothrow
shared

I _think_ that it's supposed to be there
----------------------------------------
cent
ucent

I think that they might not supposed to be keywords anymore
-----------------------------------------------------------
cdouble
cfloat
creal
delete
idouble
ifloat
ireal
foreach_reverse

Everything under "definitely" appears to be used in TDPL as keywords but not 
listed as them. cent and ucent aren't listed, but as far as I know are still 
keywords (albeit not implemented yet). The ones that are missing which I 
think have been removed are still listed in the online docs' list of 
keywards but not in the book. IIRC, the c/i floating points got moved to 
phobos; according to TDPL, delete was deprecated (though I hadn't picked up 
on that); and I believe that foreach_reverse has been deprecated in favor of 
using the combination of foreach and retro. So, TDPL is missing at least 
some keywords in its list, and the online docs have too many.

In any case, I figured that it would be helpful if any errors in TDPL could 
be pointed out, since it could be helpful to Andrei and could be helpful to 
those reading it if the error isn't obvious. However, I certainly do _not_ 
want to in any way indicate displeasure with the book. It's quite good. It's 
just that it does appear to have some errors in it that snuck through.

- Jonathan M Davis
Jun 21 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

An online Errata Corrige will be very useful.

 and I believe that foreach_reverse has been deprecated in favor of 
 using the combination of foreach and retro.
How do you write this? foreach_reverse (i; 0 .. 10) Bye, bearophile
Jun 21 2010
parent reply Adam Ruppe <destructionator gmail.com> writes:
On 6/21/10, bearophile <bearophileHUGS lycos.com> wrote:
 How do you write this?
 foreach_reverse (i; 0 .. 10)
foreach(i; retro(iota(0, 10))) { } ?
Jun 21 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam Ruppe:
 foreach(i; retro(iota(0, 10))) { }
Oh, right! Or even just: foreach (i; retro(iota(10))) {} But abstraction has a cost, see below. I have written three test programs. ---------------- // test1 import std.c.stdio: printf; void main() { enum int N = 100_000_000; int count; for (int i; i < N; i++) count++; printf("%d\n", count); } Asm of the inner code of the test1, opt version: 5: inc ECX inc EAX cmp EAX,05F5E100h jb L5 ---------------- // test2 import std.c.stdio: printf; void main() { enum int N = 100_000_000; int count; foreach_reverse (i; 0 .. N) count++; printf("%d\n", count); } Asm of the inner code of the test2, opt version: LF: dec ECX inc EDX mov EAX,ECX inc EAX jg LF ---------------- // test3 import std.c.stdio: printf; import std.range: iota, retro; void main() { enum int N = 100_000_000; int count; foreach (i; retro(iota(N))) count++; printf("%d\n", count); } Asm of the inner code of the test3, opt version: L6A: inc EBX lea EAX,010h[ESP] call near ptr _D3std5range145__T4TakeTS3std5range112__T8SequenceVAyaa27_612e6669656c645b305d202b206e202a20612eD0677AACB4B6BC826B92E7DBB9E1E359 cmp dword ptr 020h[ESP],0 jne L6A _D3std5range145__T4TakeTS3std5range112__T8SequenceVAyaa27_612e6669656c645b305d202b206e202a20612eD0677AACB4B6BC826B92E7DBB9E1E359 comdat L0: sub ESP,01Ch mov ECX,offset FLAT:_D3std5range145__T4TakeTS3std5range112__T8SequenceVAyaa27_612e6669656c645b305d202b206e202a20612e0B5C6D6E0C89B8D48DF56A414048DB6F push EBX push ESI mov ESI,EAX mov EDX,010h[ESI] mov 0Ch[ESP],EAX neg EDX sbb EDX,EDX neg EDX xor DL,1 mov 010h[ESP],ECX je L46 mov EDX,ECX push dword ptr FLAT:_DATA[064h] push dword ptr FLAT:_DATA[060h] push 051Fh mov EAX,018h[ESP] mov EBX,018h[ESP] call EDX push EDX push EAX call near ptr _D3std9contracts7bailOutFAyaixAaZv L46: dec dword ptr 010h[ESI] pop ESI pop EBX add ESP,01Ch ret _D3std9contracts7bailOutFAyaixAaZv is extern. ------------------ Running time, best of 3, seconds: test1: 0.31 test1 opt: 0.07 test2: 0.31 test2 opt: 0.12 test3: 6.38 test3 opt: 0.52 not opt version = dmd (no other option) opt version = dmd -O -release -inline Compile times opt version, seconds: test1: 0.05 test2: 0.05 test3: 0.28 So with the current dmd compiler in the inner loop in a performance-critical routine you can't use foreach(retro(iota(N))). In future a D compiler can recognize and optimize such usage of foreach(iota()) and foreach(retro(iota())) as ShedSkin does with usage of xrange()/range() in a loop. Bye, bearophile
Jun 21 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 04:06 PM, bearophile wrote:
 Adam Ruppe:
 foreach(i; retro(iota(0, 10))) { }
Oh, right! Or even just: foreach (i; retro(iota(10))) {} But abstraction has a cost, see below. I have written three test programs.
Nice work. iota() currently uses the formula initial + i * step to compute the ith element. This is to make sure that iota works properly with floating point numbers as well as integers. We should specialize iota for integrals to use increment, which should count for some efficiency gains (currently the optimizer cannot figure out the equivalence, so it generates the multiply and add in the loop). If efficiency is still sub-par, retro could detect that it's working with iota and generate specialized code. That's not too difficult; for integers, retro(iota(a, b)) could actually be a rewrite to iota(b - 1, a, -1). Figuring out all corner cases, steps greater than 1, and what to do for floating point numbers is doable but not trivial either, and works against modularity. Anyway, it does look like it's all about an implementation matter. Andrei
Jun 21 2010
parent reply Leandro Lucarella <luca llucax.com.ar> writes:
Andrei Alexandrescu, el 21 de junio a las 17:43 me escribiste:
 If efficiency is still sub-par, retro could detect that it's working
 with iota and generate specialized code. That's not too difficult;
 for integers, retro(iota(a, b)) could actually be a rewrite to
 iota(b - 1, a, -1). Figuring out all corner cases, steps greater
 than 1, and what to do for floating point numbers is doable but not
 trivial either, and works against modularity. Anyway, it does look
 like it's all about an implementation matter.
I'm scared, I've heard that in C++ so many times... =) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- HOMBRE DESNUDO AMENAZA A LOS VECINOS CON UNA "KATANA" DESDE SU BALCON -- Crónica TV
Jun 21 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 06:35 PM, Leandro Lucarella wrote:
 Andrei Alexandrescu, el 21 de junio a las 17:43 me escribiste:
 If efficiency is still sub-par, retro could detect that it's working
 with iota and generate specialized code. That's not too difficult;
 for integers, retro(iota(a, b)) could actually be a rewrite to
 iota(b - 1, a, -1). Figuring out all corner cases, steps greater
 than 1, and what to do for floating point numbers is doable but not
 trivial either, and works against modularity. Anyway, it does look
 like it's all about an implementation matter.
I'm scared, I've heard that in C++ so many times... =)
Particularly in conjunction with iostreams. Their slow speed has been an implementation issue for, what, 26 years and still going strong. :o) Fortunately, in the case of iota, it's pretty clear what needs to be done. Andrei
Jun 21 2010
prev sibling parent Norbert Nemec <Norbert Nemec-online.de> writes:
On 22/06/10 00:35, Leandro Lucarella wrote:
 Andrei Alexandrescu, el 21 de junio a las 17:43 me escribiste:
 If efficiency is still sub-par, retro could detect that it's working
 with iota and generate specialized code. That's not too difficult;
 for integers, retro(iota(a, b)) could actually be a rewrite to
 iota(b - 1, a, -1). Figuring out all corner cases, steps greater
 than 1, and what to do for floating point numbers is doable but not
 trivial either, and works against modularity. Anyway, it does look
 like it's all about an implementation matter.
I'm scared, I've heard that in C++ so many times... =)
Writing an efficient library is a complex task. No language will ever change that. The beauty of D is that this complexity can be hidden from the user (unlike in C++ where error messages become increasingly ugly).
Jun 23 2010
prev sibling next sibling parent reply Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
On 21/06/2010 20:09, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL. In fact,
 from what I've read so far, it's absolutely fantastic and quite possibly the
 most entertaining programming book that I've read in addition to being quite
 informative about D. However, no one's perfect (Andrei included), and there
 are bound to be errors in the book which didn't get caught.

 My thought was that we could point out any errors that we've found so that
 Andrei can get them fixed in future printings and/or we can find out that
 they aren't actually errors.

 The only errors that I've found so far have been omissions in the list of
 keywords on page 31. I'm listing them according to my understanding of
 whether they're still keywords, since I think that some have been removed as
 keywords or at least are no longer supposed to be keywords.

 Definitely should be there
 --------------------------
 immutable
 lazy
 pure
 nothrow
 shared

 I _think_ that it's supposed to be there
 ----------------------------------------
 cent
 ucent

 I think that they might not supposed to be keywords anymore
 -----------------------------------------------------------
 cdouble
 cfloat
 creal
 delete
 idouble
 ifloat
 ireal
 foreach_reverse

 Everything under "definitely" appears to be used in TDPL as keywords but not
 listed as them. cent and ucent aren't listed, but as far as I know are still
 keywords (albeit not implemented yet). The ones that are missing which I
 think have been removed are still listed in the online docs' list of
 keywards but not in the book. IIRC, the c/i floating points got moved to
 phobos; according to TDPL, delete was deprecated (though I hadn't picked up
 on that); and I believe that foreach_reverse has been deprecated in favor of
 using the combination of foreach and retro. So, TDPL is missing at least
 some keywords in its list, and the online docs have too many.

 In any case, I figured that it would be helpful if any errors in TDPL could
 be pointed out, since it could be helpful to Andrei and could be helpful to
 those reading it if the error isn't obvious. However, I certainly do _not_
 want to in any way indicate displeasure with the book. It's quite good. It's
 just that it does appear to have some errors in it that snuck through.

 - Jonathan M Davis
Good Idea! I must admit I skipped over that table, didn't look overly interesting as tables go (><) but good catch! There is only one mention of lazy evaluation in the index and it doesn't mention the lazy k/w at all. I seem to remember Andrei dislikes it, but also that there is another way to get function params to be evaluated lazily without using it. immutable, nothrow, pure and shared are definitely oversights though. I've not spotted anything D-specific myself yet, I'm not a particularly speedy reader ^^ A...
Jun 21 2010
next sibling parent reply =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 21-06-2010 o 21:57:49 Alix Pexton <alix.DOT.pexton gmail.dot.com>  =

napisa=B3(a):

 There is only one mention of lazy evaluation in the index and it doesn=
't =
 mention the lazy k/w at all. I seem to remember Andrei dislikes it, bu=
t =
 also that there is another way to get function params to be evaluated =
=
 lazily without using it.
Yeah, speaking of which - what happened to that proposal*? *The proposal AFAIR was (correct me if wrong): if a function has a = parameterless delegate as a parameter, then on the call site any = expression in the delegate slot is implicitly turned into a delegate. I = = think the delegate ought to be pure to make the magic happen. Yeah, speaking of which - do/will we have pure delegates? Tomek
Jun 21 2010
next sibling parent BCS <none anon.com> writes:
Hello Tomek,

 I think the delegate ought to be pure to make the magic happen.
 
That would be a god idea if the feature were strictly for lazy (no cost unless you need it) evaluation but there are other use that need to be able to cause side effects. -- ... <IXOYE><
Jun 21 2010
prev sibling parent Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
On 21/06/2010 21:51, Tomek Sowiñski wrote:
 Dnia 21-06-2010 o 21:57:49 Alix Pexton <alix.DOT.pexton gmail.dot.com>
 napisa³(a):

 There is only one mention of lazy evaluation in the index and it
 doesn't mention the lazy k/w at all. I seem to remember Andrei
 dislikes it, but also that there is another way to get function params
 to be evaluated lazily without using it.
Yeah, speaking of which - what happened to that proposal*? *The proposal AFAIR was (correct me if wrong): if a function has a parameterless delegate as a parameter, then on the call site any expression in the delegate slot is implicitly turned into a delegate. I think the delegate ought to be pure to make the magic happen. Yeah, speaking of which - do/will we have pure delegates? Tomek
This is the "trick" I was refering to, from a post by the programmer formerly known as downs... Amusing D facts: typesafe variadic arrays are lazy!
 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }
It's true! :)
A...
Jun 22 2010
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 02:57 PM, Alix Pexton wrote:
 There is only one mention of lazy evaluation in the index and it doesn't
 mention the lazy k/w at all. I seem to remember Andrei dislikes it, but
 also that there is another way to get function params to be evaluated
 lazily without using it.
lazy is quite, no, _very_ ill-defined. Walter and I decided to not mention it in the book and leave room for either a better definition of lazy or a feature that obviates it. Andrei
Jun 21 2010
prev sibling next sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
I was biting my tongue on the subject, but on page 73 the grammar for 
the do while loop has a semicolon at the end. AAHHHHHHHHHHHHH!!!!!!!! 
THERE IS NOOOOOOO SEMICOLON AT THE END.

Wow. Sorry. This is a pet peeve of mine.
Jun 21 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 03:32 PM, Ellery Newcomer wrote:
 I was biting my tongue on the subject, but on page 73 the grammar for
 the do while loop has a semicolon at the end. AAHHHHHHHHHHHHH!!!!!!!!
 THERE IS NOOOOOOO SEMICOLON AT THE END.

 Wow. Sorry. This is a pet peeve of mine.
Can't help that, sorry... Andrei
Jun 21 2010
parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Andrei Alexandrescu wrote:

 On 06/21/2010 03:32 PM, Ellery Newcomer wrote:
 I was biting my tongue on the subject, but on page 73 the grammar for
 the do while loop has a semicolon at the end. AAHHHHHHHHHHHHH!!!!!!!!
 THERE IS NOOOOOOO SEMICOLON AT THE END.

 Wow. Sorry. This is a pet peeve of mine.
Can't help that, sorry... Andrei
Well, while I, personally, would put a semicolon there (it feels naked to me without one), dmd doesn't actually seem to require it. But TDPL says that the semicolon is required. So, it does appear to be an error in the text. Of course, there's no helping his pet peeve regardless, but the semicolon doesn't appear to be required. - Jonathan M Davis
Jun 22 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/22/2010 04:14 PM, Jonathan M Davis wrote:
 Andrei Alexandrescu wrote:

 On 06/21/2010 03:32 PM, Ellery Newcomer wrote:
 I was biting my tongue on the subject, but on page 73 the grammar for
 the do while loop has a semicolon at the end. AAHHHHHHHHHHHHH!!!!!!!!
 THERE IS NOOOOOOO SEMICOLON AT THE END.

 Wow. Sorry. This is a pet peeve of mine.
Can't help that, sorry... Andrei
Well, while I, personally, would put a semicolon there (it feels naked to me without one), dmd doesn't actually seem to require it. But TDPL says that the semicolon is required. So, it does appear to be an error in the text. Of course, there's no helping his pet peeve regardless, but the semicolon doesn't appear to be required. - Jonathan M Davis
Walter, was that intentional? The grammar has no semicolon but the example does. That makes the example wrong because you agreed there is no solitary semicolon statement in D, and TDPL does mention that. IMHO the semicolon makes for more robust code. Consider: do { ... lotsa code ... } while (fun(i)) ++i; A maintainer might see the while and conclude that ++i; was meant to be the loop, indent it, and call it a day. The absence of the semicolon thus created a contextual dependency on the presence of the "do" keyword upstream. Walter, can we require a semicolon please? Andrei
Jun 22 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
you agreed there is no solitary semicolon statement in D,<
This compiles, is this a solitary semicolon statement? void main() { goto FOO; FOO:; }
 Walter, can we require a semicolon please?
+1 Bye, bearophile
Jun 22 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/22/2010 04:53 PM, bearophile wrote:
 Andrei Alexandrescu:
 you agreed there is no solitary semicolon statement in D,<
This compiles, is this a solitary semicolon statement? void main() { goto FOO; FOO:; }
Yes. It shouldn't compile. Walter and I agreed that solitary semicolons are useless (you can always use {} as an empty statement and that actually makes things clearer to everyone), but it's a low-priority issue so he hasn't implemented that yet. Andrei
Jun 22 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:
 void main() {
      goto FOO;
      FOO:;
 }
Yes. It shouldn't compile. Walter and I agreed that solitary semicolons are useless (you can always use {} as an empty statement and that actually makes things clearer to everyone),
I have had to use a LABEL:; in D code, to implement a finite state machine. So I guess I'll have to write it like this: LABEL: {} Bye, bearophile
Jun 22 2010
parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Andrei:
 void main() {
      goto FOO;
      FOO:;
 }
Yes. It shouldn't compile. Walter and I agreed that solitary semicolons are useless (you can always use {} as an empty statement and that actually makes things clearer to everyone),
I have had to use a LABEL:; in D code, to implement a finite state machine. So I guess I'll have to write it like this: LABEL: {} Bye, bearophile
I think the ; is part of the label statement. If not, it should be removed entirely.
Jun 23 2010
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Wed, 23 Jun 2010 11:56:12 +0200, Don wrote:

 bearophile wrote:
 Andrei:
 void main() {
      goto FOO;
      FOO:;
 }
Yes. It shouldn't compile. Walter and I agreed that solitary semicolons are useless (you can always use {} as an empty statement and that actually makes things clearer to everyone),
I have had to use a LABEL:; in D code, to implement a finite state machine. So I guess I'll have to write it like this: LABEL: {} Bye, bearophile
I think the ; is part of the label statement. If not, it should be removed entirely.
This does not compile: void main() { goto Lfoo; Lfoo: } test.d(5): found '}' instead of statement It seems to me like it should be valid code, but I'm not sure it's worth making it a special case. -Lars
Jun 23 2010
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/23/2010 04:56 AM, Don wrote:
 bearophile wrote:
 Andrei:
 void main() {
 goto FOO;
 FOO:;
 }
Yes. It shouldn't compile. Walter and I agreed that solitary semicolons are useless (you can always use {} as an empty statement and that actually makes things clearer to everyone),
I have had to use a LABEL:; in D code, to implement a finite state machine. So I guess I'll have to write it like this: LABEL: {} Bye, bearophile
I think the ; is part of the label statement. If not, it should be removed entirely.
Fortunately there's no label statement. A label is a distinct entity and may precede any statement. Andrei
Jun 23 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Andrei Alexandrescu wrote:

 
 Walter, was that intentional? The grammar has no semicolon but the
 example does. That makes the example wrong because you agreed there is
 no solitary semicolon statement in D, and TDPL does mention that.
 
 IMHO the semicolon makes for more robust code. Consider:
 
 do
 {
      ... lotsa code ...
 }
 while (fun(i))
 ++i;
 
 A maintainer might see the while and conclude that ++i; was meant to be
 the loop, indent it, and call it a day. The absence of the semicolon
 thus created a contextual dependency on the presence of the "do" keyword
 upstream.
 
 Walter, can we require a semicolon please?
 
 
 Andrei
I have zero problem requiring a semicolon (I'd prefer it actually), but I believe that a lone semicolon is generally a perfectly valid statement in D as long as it's not where optional braces could be. Per the grammar: Statement: ; NonEmptyStatement ScopeBlockStatement I believe that all the constructs with optional braces have a ScopBlockStatement for their body and therefore can't have a lone semicolon. But a statement by itself can be a lone semicolon. Though why you'd do that, I don't know. The only place that I've run into that being useful has been with macros (which don't exist in D). - Jonathan M Davis
Jun 22 2010
prev sibling next sibling parent reply Rick Trelles <RTrelles bellsouth.net> writes:
Saving a keystroke, if it is in sound and clear way, is a plus.
At least the option to save the keystroke should be maintained.

I don't see now any advantages in using a pair of braces over a single 
semicolon for a null statement, but why not keep it both ways?

I never liked the semicolon after while() but surely it wouldn't hurt to 
interpret it as a null statement for those who are used to it.

By the way, I always glue the closing bracket to while

do{

. . .

}while( . . . )  // plus ";" if coding in C


Rick Trelles
Jun 23 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/23/2010 02:11 AM, Rick Trelles wrote:
 Saving a keystroke, if it is in sound and clear way, is a plus.
 At least the option to save the keystroke should be maintained.

 I don't see now any advantages in using a pair of braces over a single
 semicolon for a null statement, but why not keep it both ways?
We've all seen that requiring "{}" after the likes of if, while etc. are very beneficial for readability. Then why not generalize that? As far as I can tell the only vestigial use of the lone ";" is with labels that don't precede any instruction (a very rare case). At this point, ";" needs more justification to stay than to go.
 I never liked the semicolon after while() but surely it wouldn't hurt to
 interpret it as a null statement for those who are used to it.

 By the way, I always glue the closing bracket to while

 do{

 . . .

 }while( . . . ) // plus ";" if coding in C


 Rick Trelles
That's great, except for those who enjoy "brace on its own line" formatting style. For those, the "}while" would look jarring. Andrei
Jun 23 2010
parent reply Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
On 23/06/2010 16:24, Andrei Alexandrescu wrote:
 On 06/23/2010 02:11 AM, Rick Trelles wrote:
 Saving a keystroke, if it is in sound and clear way, is a plus.
 At least the option to save the keystroke should be maintained.

 I don't see now any advantages in using a pair of braces over a single
 semicolon for a null statement, but why not keep it both ways?
We've all seen that requiring "{}" after the likes of if, while etc. are very beneficial for readability. Then why not generalize that? As far as I can tell the only vestigial use of the lone ";" is with labels that don't precede any instruction (a very rare case). At this point, ";" needs more justification to stay than to go.
 I never liked the semicolon after while() but surely it wouldn't hurt to
 interpret it as a null statement for those who are used to it.

 By the way, I always glue the closing bracket to while

 do{

 . . .

 }while( . . . ) // plus ";" if coding in C


 Rick Trelles
That's great, except for those who enjoy "brace on its own line" formatting style. For those, the "}while" would look jarring. Andrei
I find that the "}while(..." style is the best way to highlight that you are looking a a do...while and not a regular while loop, that it is jarring is exactly the point ^^ Making the the semicolon on the end a requirement helps if you are familiar with D and know it is not allowed on a regular while, but the less enlightened might see a classic bug pattern where there isn't one and try to "maintain" it away >< In some ways I think it was a mistake in to reuse while in the first place, but that was a decision that was made a loong time before D... A...
Jun 23 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Alix Pexton:
 In some ways I think it was a mistake in to reuse while in the first 
 place, but that was a decision that was made a loong time before D...
Pascal-like languages use repeat-until, but I prefer the C do-while because the condition in repeat-until is the opposite of the one you use in a while loop, and every time I use repeat-until I have to remember what's the correct stopping condition to write. Bye, bearophile
Jun 23 2010
parent reply eles <eles eles.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 Alix Pexton:
 In some ways I think it was a mistake in to reuse while in the
first
 place, but that was a decision that was made a loong time before
D...
 Pascal-like languages use repeat-until, but I prefer the C do-while
because the condition in repeat-until is the opposite of the one you use in a while loop, and every time I use repeat-until I have to remember what's the correct stopping condition to write. Quite the oposite here. When I have a loop like that, I think rather about the exit condition (so in terms of "repeat/until"). This is why I often write: do{ //code } while(!([exit_condition_here])); I also think re-using while() in the do ... while loop is a mistake, exactly because of difficulties arising in code maintenance. I would like to have another keyword for that, or maybe the "repeat/ until" loop all-together. It is a shame that compatibility issues prevail over quality and improvement. Ditching the do...while loop could be unacceptable now, but why do not propose a better alternative mechanism? That way, we would have both compatibility and quality. eles
 Bye,
 bearophile
Jun 23 2010
parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
eles wrote:

 It is a shame that compatibility issues prevail over quality and
 improvement. Ditching the do...while loop could be unacceptable now,
 but why do not propose a better alternative mechanism? That way, we
 would have both compatibility and quality.
 
 eles
Quality prevails over compatibility when the quality gain is deemed to exceed the problems incurred by losing compatibility. In this case, do-while works just fine. Lots of people are used to using it and have never even heard of repeat-until, having never used Pascal or any other language that used it. At this point, C's influence far outweights Pascal's. Also, AFAIK, do-while is not generally a major source of bugs. As such, while another construct might be better, since the current one isn't much of a problem, it's not worth breaking compatibility. If it were shown that do- while was a big problem, then it might be. But at this point, do-while works just fine, so it's not worth changing it. - Jonathan M Davis
Jun 23 2010
parent eles <eles eles.com> writes:
 I did not try to start a polemic, but to give something to think about. There
are more opinions on the matter and, as you may see, mine differs of yours. Is
not a tragedy.

 However, I think one should be more aware when supporting habit per se.

 Maybe adding "until" as an aliasing for "while not" would you seem more
acceptable? Or, at least, accepting "do{/* code */}aslongas(/*condition*/);" as
an alternative "do{/* code */}while(/*condition*/);" would be less disruptive?

 That way, people could use "do/while", but this will open the door for "do/
aslongas", if this is considered suitable. This will also avoid ambiguous cases
like pointed out in this thread (i.e. the danger of interpreting "while(/
*condition*/;i++" as a ";" bug). This will break no compatibility.

 Robustness of relying solely on the code indentation ("}while();" instead of
"while();") is not persuasive for me. Why dismissing an opportunity to avoid a
potential bug?

eles


== Quote from Jonathan M Davis (jmdavisProg gmail.com)'s article
 Quality prevails over compatibility when the quality gain is deemed to
 exceed the problems incurred by losing compatibility.
 In this case, do-while works just fine. Lots of people are used to using it
 and have never even heard of repeat-until, having never used Pascal or any
 other language that used it. At this point, C's influence far outweights
 Pascal's.
 Also, AFAIK, do-while is not generally a major source of bugs. As such,
 while another construct might be better, since the current one isn't much of
 a problem, it's not worth breaking compatibility. If it were shown that do-
 while was a big problem, then it might be. But at this point, do-while works
 just fine, so it's not worth changing it.
 - Jonathan M Davis
Jun 24 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/23/2010 05:44 PM, Alix Pexton wrote:
 On 23/06/2010 16:24, Andrei Alexandrescu wrote:
 On 06/23/2010 02:11 AM, Rick Trelles wrote:
 Saving a keystroke, if it is in sound and clear way, is a plus.
 At least the option to save the keystroke should be maintained.

 I don't see now any advantages in using a pair of braces over a single
 semicolon for a null statement, but why not keep it both ways?
We've all seen that requiring "{}" after the likes of if, while etc. are very beneficial for readability. Then why not generalize that? As far as I can tell the only vestigial use of the lone ";" is with labels that don't precede any instruction (a very rare case). At this point, ";" needs more justification to stay than to go.
 I never liked the semicolon after while() but surely it wouldn't hurt to
 interpret it as a null statement for those who are used to it.

 By the way, I always glue the closing bracket to while

 do{

 . . .

 }while( . . . ) // plus ";" if coding in C


 Rick Trelles
That's great, except for those who enjoy "brace on its own line" formatting style. For those, the "}while" would look jarring. Andrei
I find that the "}while(..." style is the best way to highlight that you are looking a a do...while and not a regular while loop, that it is jarring is exactly the point ^^ Making the the semicolon on the end a requirement helps if you are familiar with D and know it is not allowed on a regular while, but the less enlightened might see a classic bug pattern where there isn't one and try to "maintain" it away >< In some ways I think it was a mistake in to reuse while in the first place, but that was a decision that was made a loong time before D... A...
Walter agreed to fix do-while to require a semicolon. Andrei
Jun 23 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 Walter agreed to fix do-while to require a semicolon.
Good. This was the relative bug: http://d.puremagic.com/issues/show_bug.cgi?id=4374 Bye, bearophile
Jun 23 2010
prev sibling parent reply "Rory McGuire" <rmcguire neonova.co.za> writes:
On Tue, 22 Jun 2010 23:37:59 +0200, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter, can we require a semicolon please?
+1 With the semi colon missing its as bad as: for (;i<100;i++); writeln(i); esp. with large amount of code
 Andrei
Rory
Jun 23 2010
parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Rory McGuire wrote:

 On Tue, 22 Jun 2010 23:37:59 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Walter, can we require a semicolon please?
+1 With the semi colon missing its as bad as: for (;i<100;i++); writeln(i); esp. with large amount of code
 Andrei
Rory
It's not that bad. for(; i < 100; ++i); writeln(i); would be a bug (if it were legal) because you'd expect the writeln() to be part of the loop when it isn't. The loop wouldn't be run like you'd expect it to, and it's hard to catch. do { ... } while(test) does not have that problem. The problem you run into is this: do { ... } while(test) { ... } If you're _really_ not paying attention, you'd think that the second set of braces started a while loop. But since you'd have to have way more spacing than makes sense for it to happen, it becomes way more obvious and is not the same level of problem. However, I do think that it _is_ a problem, and the above example could definitely be confusing if you're just quickly scanning over code. I don't see any real reason to allow the lack of semicolon, and I do think that it's a problem, but I don't think that it's a problem on the same level as allowing a semicolon to be used as an empty body for an if statement or loop. - Jonathan M Davis
Jun 23 2010
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
Jonathan M Davis wrote:
 Well, while I, personally, would put a semicolon there (it feels naked to me 
 without one), dmd doesn't actually seem to require it. But TDPL says that 
 the semicolon is required. So, it does appear to be an error in the text. Of 
 course, there's no helping his pet peeve regardless, but the semicolon 
 doesn't appear to be required.
For reference for this discussion, the current grammar does not require it: http://www.digitalmars.com/d/2.0/statement.html#DoStatement The C grammar does require it: do statement while ( expression ) ;
Jun 23 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/23/2010 11:40 AM, Walter Bright wrote:
 Jonathan M Davis wrote:
 Well, while I, personally, would put a semicolon there (it feels naked
 to me without one), dmd doesn't actually seem to require it. But TDPL
 says that the semicolon is required. So, it does appear to be an error
 in the text. Of course, there's no helping his pet peeve regardless,
 but the semicolon doesn't appear to be required.
For reference for this discussion, the current grammar does not require it: http://www.digitalmars.com/d/2.0/statement.html#DoStatement The C grammar does require it: do statement while ( expression ) ;
I mistakingly assumed D followed C in that regard. Given the argument stated in this thread (that absent semicolons require more context to be absorbed while reading), do you agree that D should make the semicolon required? Andrei
Jun 23 2010
next sibling parent Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
On 23/06/2010 17:51, Andrei Alexandrescu wrote:
 On 06/23/2010 11:40 AM, Walter Bright wrote:
 Jonathan M Davis wrote:
 Well, while I, personally, would put a semicolon there (it feels naked
 to me without one), dmd doesn't actually seem to require it. But TDPL
 says that the semicolon is required. So, it does appear to be an error
 in the text. Of course, there's no helping his pet peeve regardless,
 but the semicolon doesn't appear to be required.
For reference for this discussion, the current grammar does not require it: http://www.digitalmars.com/d/2.0/statement.html#DoStatement The C grammar does require it: do statement while ( expression ) ;
I mistakingly assumed D followed C in that regard. Given the argument stated in this thread (that absent semicolons require more context to be absorbed while reading), do you agree that D should make the semicolon required? Andrei
++vote A...
Jun 23 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 I mistakingly assumed D followed C in that regard. Given the argument  
 stated in this thread (that absent semicolons require more context to be  
 absorbed while reading), do you agree that D should make the semicolon  
 required?
Yes -- Simen
Jun 24 2010
prev sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Wed, 23 Jun 2010 11:51:40 -0500, Andrei Alexandrescu wrote:

 On 06/23/2010 11:40 AM, Walter Bright wrote:
 Jonathan M Davis wrote:
 Well, while I, personally, would put a semicolon there (it feels naked
 to me without one), dmd doesn't actually seem to require it. But TDPL
 says that the semicolon is required. So, it does appear to be an error
 in the text. Of course, there's no helping his pet peeve regardless,
 but the semicolon doesn't appear to be required.
For reference for this discussion, the current grammar does not require it: http://www.digitalmars.com/d/2.0/statement.html#DoStatement The C grammar does require it: do statement while ( expression ) ;
I mistakingly assumed D followed C in that regard. Given the argument stated in this thread (that absent semicolons require more context to be absorbed while reading), do you agree that D should make the semicolon required?
Absolutely. -Lars
Jun 24 2010
prev sibling next sibling parent reply Spacen Jasset <spacenjasset yahoo.co.uk> writes:
I am only on page ten, I believe I saw a minor typo somewhere in the 
preface, that's all so far. I look forward to pondering the rest in the 
coming days.

oh yes.

Preface
"D is a language that attempts to consistently do the right thing within 
the constraints it choose: sys...." etc

missing s, I gues.
Jun 21 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 05:35 PM, Spacen Jasset wrote:
 I am only on page ten, I believe I saw a minor typo somewhere in the
 preface, that's all so far. I look forward to pondering the rest in the
 coming days.

 oh yes.

 Preface
 "D is a language that attempts to consistently do the right thing within
 the constraints it choose: sys...." etc

 missing s, I gues.
Thanks for your note. The current text uses "chose", i.e. the past tense of "to choose", so I think it is correct. Andrei
Jun 21 2010
parent Spacen Jasset <spacenjasset yahoo.co.uk> writes:
Andrei Alexandrescu wrote:
 On 06/21/2010 05:35 PM, Spacen Jasset wrote:
 I am only on page ten, I believe I saw a minor typo somewhere in the
 preface, that's all so far. I look forward to pondering the rest in the
 coming days.

 oh yes.

 Preface
 "D is a language that attempts to consistently do the right thing within
 the constraints it choose: sys...." etc

 missing s, I gues.
Thanks for your note. The current text uses "chose", i.e. the past tense of "to choose", so I think it is correct. Andrei
heh. I can't read. I loose a cookie.
Jun 21 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o). Of course we need an errata list. I was hoping I'd need to set it up later, but hey, that's a sign people actually are reading the book and care about keeping everything in check. I started an errata list in form of a community wiki at http://www.erdani.com/tdpl/errata and primed the errata with your report. Thanks very much! I'll see to it that future printings fix the issues in the errata list. Andrei
Jun 21 2010
next sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Andrei Alexandrescu wrote:

 On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o).
Well, I didn't want to post on the main D list and come across as saying that the new book is full of errors and sucks. wIt really is quite an entertaining read (for a programming book anyway) with talk of jumping through rings of syntactic fire, describing casts as well-intended genies, and plenty of other humourous descriptions. And, of course, it's quite instructive along the way. Now if I can only get my co-workers to read it... - Jonathan M Davis
Jun 21 2010
prev sibling next sibling parent reply torhu <no spam.invalid> writes:
On 22.06.2010 00:39, Andrei Alexandrescu wrote:
 I started an errata list in form of a community wiki at

 http://www.erdani.com/tdpl/errata
For those of us who have still only got the pdf version, is that the same text as the printed one? Should we report errors in the pdf version, or wait until we get the printed edition?
Jun 21 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 06:30 PM, torhu wrote:
 On 22.06.2010 00:39, Andrei Alexandrescu wrote:
 I started an errata list in form of a community wiki at

 http://www.erdani.com/tdpl/errata
For those of us who have still only got the pdf version, is that the same text as the printed one? Should we report errors in the pdf version, or wait until we get the printed edition?
The PDF on Rough Cuts is identical to the printed book. Please report straight in the errata. Andrei
Jun 21 2010
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
On page 82 of TDPL, it's talking about try/catch/finally statements, and it 
says that "all controlled statement must be block statements; that is they 
must be enclosed with braces." However, dmd does not seem to require that 
try/catch/finally blocks have braces, which is what I would expect that 
sentence to mean. C++ has that restriction for reasons that I don't 
understand, but as far as I can tell, D does not - certainly dmd doesn't 
appear to require it. Is the statement correct but refers to something else, 
or is it in error?

- Jonathan M Davis
Jun 21 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 08:47 PM, Jonathan M Davis wrote:
 On page 82 of TDPL, it's talking about try/catch/finally statements, and it
 says that "all controlled statement must be block statements; that is they
 must be enclosed with braces." However, dmd does not seem to require that
 try/catch/finally blocks have braces, which is what I would expect that
 sentence to mean. C++ has that restriction for reasons that I don't
 understand, but as far as I can tell, D does not - certainly dmd doesn't
 appear to require it. Is the statement correct but refers to something else,
 or is it in error?

 - Jonathan M Davis
That's a surprise to me. Walter, is that intentional? Andrei
Jun 21 2010
parent reply Walter Bright <newshound2 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 On 06/21/2010 08:47 PM, Jonathan M Davis wrote:
 On page 82 of TDPL, it's talking about try/catch/finally statements, 
 and it
 says that "all controlled statement must be block statements; that is 
 they
 must be enclosed with braces." However, dmd does not seem to require that
 try/catch/finally blocks have braces, which is what I would expect that
 sentence to mean. C++ has that restriction for reasons that I don't
 understand, but as far as I can tell, D does not - certainly dmd doesn't
 appear to require it. Is the statement correct but refers to something 
 else,
 or is it in error?

 - Jonathan M Davis
That's a surprise to me. Walter, is that intentional?
They do not require braces, they just require that the controlling statement not be a single ;. In the grammar, this is a ScopeStatement, which is a NonEmptyStatement or a BlockStatement. http://www.digitalmars.com/d/2.0/statement.html#ScopeStatement
Jun 22 2010
parent reply biozic <dransic free.fr> writes:
Le 22/06/10 10:54, Walter Bright a écrit :
 Andrei Alexandrescu wrote:
 On 06/21/2010 08:47 PM, Jonathan M Davis wrote:
 On page 82 of TDPL, it's talking about try/catch/finally statements,
 and it
 says that "all controlled statement must be block statements; that is
 they
 must be enclosed with braces." However, dmd does not seem to require
 that
 try/catch/finally blocks have braces, which is what I would expect that
 sentence to mean. C++ has that restriction for reasons that I don't
 understand, but as far as I can tell, D does not - certainly dmd doesn't
 appear to require it. Is the statement correct but refers to
 something else,
 or is it in error?

 - Jonathan M Davis
That's a surprise to me. Walter, is that intentional?
They do not require braces, they just require that the controlling statement not be a single ;. In the grammar, this is a ScopeStatement, which is a NonEmptyStatement or a BlockStatement. http://www.digitalmars.com/d/2.0/statement.html#ScopeStatement
Not always: http://d.puremagic.com/issues/show_bug.cgi?id=4024
Jun 22 2010
parent reply Walter Bright <newshound2 digitalmars.com> writes:
biozic wrote:
 Le 22/06/10 10:54, Walter Bright a écrit :
 Andrei Alexandrescu wrote:
 On 06/21/2010 08:47 PM, Jonathan M Davis wrote:
 On page 82 of TDPL, it's talking about try/catch/finally statements,
 and it
 says that "all controlled statement must be block statements; that is
 they
 must be enclosed with braces." However, dmd does not seem to require
 that
 try/catch/finally blocks have braces, which is what I would expect that
 sentence to mean. C++ has that restriction for reasons that I don't
 understand, but as far as I can tell, D does not - certainly dmd 
 doesn't
 appear to require it. Is the statement correct but refers to
 something else,
 or is it in error?

 - Jonathan M Davis
That's a surprise to me. Walter, is that intentional?
They do not require braces, they just require that the controlling statement not be a single ;. In the grammar, this is a ScopeStatement, which is a NonEmptyStatement or a BlockStatement. http://www.digitalmars.com/d/2.0/statement.html#ScopeStatement
Not always: http://d.puremagic.com/issues/show_bug.cgi?id=4024
Bugs in the compiler aren't errors in TDPL!
Jun 22 2010
parent biozic <dransic free.fr> writes:
Le 22/06/10 15:53, Walter Bright a écrit :
 biozic wrote:
 Le 22/06/10 10:54, Walter Bright a écrit :
 Andrei Alexandrescu wrote:
 On 06/21/2010 08:47 PM, Jonathan M Davis wrote:
 On page 82 of TDPL, it's talking about try/catch/finally statements,
 and it
 says that "all controlled statement must be block statements; that is
 they
 must be enclosed with braces." However, dmd does not seem to require
 that
 try/catch/finally blocks have braces, which is what I would expect
 that
 sentence to mean. C++ has that restriction for reasons that I don't
 understand, but as far as I can tell, D does not - certainly dmd
 doesn't
 appear to require it. Is the statement correct but refers to
 something else,
 or is it in error?

 - Jonathan M Davis
That's a surprise to me. Walter, is that intentional?
They do not require braces, they just require that the controlling statement not be a single ;. In the grammar, this is a ScopeStatement, which is a NonEmptyStatement or a BlockStatement. http://www.digitalmars.com/d/2.0/statement.html#ScopeStatement
Not always: http://d.puremagic.com/issues/show_bug.cgi?id=4024
Bugs in the compiler aren't errors in TDPL!
I totally agree. I was saying that the requirement for braces was not always intentional :S
Jun 22 2010
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Mon, Jun 21, 2010 at 3:39 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o). Of course we need an errata list. I was hoping I'd need to set it up later, but hey, that's a sign people actually are reading the book and care about keeping everything in check. I started an errata list in form of a community wiki at http://www.erdani.com/tdpl/errata and primed the errata with your report. Thanks very much! I'll see to it that future printings fix the issues in the errata list.
Will you fix all the god-awful puns too if we add those to the list? :-) Just kidding, I'm sure suffering through them helps build character or something. --bb
Jun 22 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/22/2010 01:45 PM, Bill Baxter wrote:
 On Mon, Jun 21, 2010 at 3:39 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:
 On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o). Of course we need an errata list. I was hoping I'd need to set it up later, but hey, that's a sign people actually are reading the book and care about keeping everything in check. I started an errata list in form of a community wiki at http://www.erdani.com/tdpl/errata and primed the errata with your report. Thanks very much! I'll see to it that future printings fix the issues in the errata list.
Will you fix all the god-awful puns too if we add those to the list? :-) Just kidding, I'm sure suffering through them helps build character or something.
If my puns suck I sure want to know which! Andrei
Jun 22 2010
parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Jun 22, 2010 at 11:52 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 On 06/22/2010 01:45 PM, Bill Baxter wrote:
 On Mon, Jun 21, 2010 at 3:39 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> =A0wrote:
 On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o). Of course we need an errata list=
.
 I
 was hoping I'd need to set it up later, but hey, that's a sign people
 actually are reading the book and care about keeping everything in chec=
k.
 I started an errata list in form of a community wiki at

 http://www.erdani.com/tdpl/errata

 and primed the errata with your report.

 Thanks very much! I'll see to it that future printings fix the issues i=
n
 the
 errata list.
Will you fix all the god-awful puns too if we add those to the list? =A0=
:-)
 Just kidding, I'm sure suffering through them helps build character or
 something.
If my puns suck I sure want to know which! Andrei
They're fine. I'm just kidding. "A pun is the lowest form of humor-- if you didn't think of it first." -- Oscar Levant --bb
Jun 22 2010
prev sibling next sibling parent Graham Fawcett <fawcett uwindsor.ca> writes:
On Tue, 22 Jun 2010 11:45:39 -0700, Bill Baxter wrote:

 On Mon, Jun 21, 2010 at 3:39 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o). Of course we need an errata list. I was hoping I'd need to set it up later, but hey, that's a sign people actually are reading the book and care about keeping everything in check. I started an errata list in form of a community wiki at http://www.erdani.com/tdpl/errata and primed the errata with your report. Thanks very much! I'll see to it that future printings fix the issues in the errata list.
Will you fix all the god-awful puns too if we add those to the list? :-) Just kidding, I'm sure suffering through them helps build character or something.
Awful puns, you say? Now I have to buy a copy! Graham
Jun 22 2010
prev sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Bill Baxter wrote:

 On Mon, Jun 21, 2010 at 3:39 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 On 06/21/2010 02:09 PM, Jonathan M Davis wrote:
 Okay. I am in no way trying to say anything negative about TDPL.
[snip] You are being too kind about this :o). Of course we need an errata list. I was hoping I'd need to set it up later, but hey, that's a sign people actually are reading the book and care about keeping everything in check. I started an errata list in form of a community wiki at http://www.erdani.com/tdpl/errata and primed the errata with your report. Thanks very much! I'll see to it that future printings fix the issues in the errata list.
Will you fix all the god-awful puns too if we add those to the list? :-) Just kidding, I'm sure suffering through them helps build character or something. --bb
Aw. Those were awesome. Of course, I love puns, so I'm not about to complain about them unless they're really bad, and Andrei's were good. - Jonathan M Davis
Jun 22 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

That's not too difficult; for integers, retro(iota(a, b)) could actually be a
rewrite to iota(b - 1, a, -1).<
This is good. In my dlibs the xchain converts xchain(xchain(x, y), z) and similar into xchain(x, y, z).
Figuring out all corner cases, steps greater than 1, and what to do for
floating point numbers is doable but not trivial either, and works against
modularity.<
I suggest to focus on the most important case, integer/uint indexes (and +1 or -1 increment). My post has shown some different problems: - A longer compilation time (and binary size) - A 1/10 performance when the code is compiled in standard way, this is bad - a smaller performance when the code is compiled in optimized mode. The asm of the opt version shows calls to two or more functions inside the loop, and one of those functions is not so small, this probably reduces performance more than an extra inlined product. So in my opinion getting rid of those calls (inlining them) is more important if you want a faster retro(iota). ------------------------ I have added your last version: // test4 import std.c.stdio: printf; import std.range: iota; void main() { enum int N = 100_000_000; int count; foreach (i; iota(N - 1, 0, -1)) count++; printf("%d\n", count); } Running time, best of 3, seconds: test1: 0.31 test1 opt: 0.07 test2: 0.31 test2 opt: 0.12 test3: 6.38 test3 opt: 0.52 test4: 4.70 test4 opt: 1.25 not opt version = dmd (no other option) opt version = dmd -O -release -inline Compile times opt version, seconds: test1: 0.05 test2: 0.05 test3: 0.28 test4: 0.29 The compilation time is the same, the not-opt test4 is faster than not-opt test3, but opt test4 is quite slower than opt test3. Bye, bearophile
Jun 21 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 08:28 PM, bearophile wrote:
 Andrei Alexandrescu:

 That's not too difficult; for integers, retro(iota(a, b)) could actually be a
rewrite to iota(b - 1, a, -1).<
This is good. In my dlibs the xchain converts xchain(xchain(x, y), z) and similar into xchain(x, y, z).
 Figuring out all corner cases, steps greater than 1, and what to do for
floating point numbers is doable but not trivial either, and works against
modularity.<
I suggest to focus on the most important case, integer/uint indexes (and +1 or -1 increment). My post has shown some different problems: - A longer compilation time (and binary size) - A 1/10 performance when the code is compiled in standard way, this is bad - a smaller performance when the code is compiled in optimized mode. The asm of the opt version shows calls to two or more functions inside the loop, and one of those functions is not so small, this probably reduces performance more than an extra inlined product. So in my opinion getting rid of those calls (inlining them) is more important if you want a faster retro(iota). ------------------------ I have added your last version: // test4 import std.c.stdio: printf; import std.range: iota; void main() { enum int N = 100_000_000; int count; foreach (i; iota(N - 1, 0, -1)) count++; printf("%d\n", count); } Running time, best of 3, seconds: test1: 0.31 test1 opt: 0.07 test2: 0.31 test2 opt: 0.12 test3: 6.38 test3 opt: 0.52 test4: 4.70 test4 opt: 1.25 not opt version = dmd (no other option) opt version = dmd -O -release -inline Compile times opt version, seconds: test1: 0.05 test2: 0.05 test3: 0.28 test4: 0.29 The compilation time is the same, the not-opt test4 is faster than not-opt test3, but opt test4 is quite slower than opt test3. Bye, bearophile
Thanks. Hmm. I redefined iota as follows: struct Iota(N, S) if ((isIntegral!N || isPointer!N) && isIntegral!S) { private N current, pastLast; private S step; this(N current, N pastLast, S step) { enforce(step != 0 && current != pastLast); this.current = current; this.step = step; if (step > 0) { this.pastLast = pastLast - 1; this.pastLast -= (this.pastLast - current) % step; } else { this.pastLast = pastLast + 1; this.pastLast += (this.pastLast - current) % step; } this.pastLast += step; } bool empty() const { return current == pastLast; } N front() { return current; } alias front moveFront; void popFront() { current += step; } N back() { return pastLast - step; } alias back moveBack; void popBack() { pastLast -= step; } Iota save() { return this; } N opIndex(size_t n) { return current + step * n; } size_t length() { return (pastLast - current) / step; } } Iota!(CommonType!(B, E), S) iota(B, E, S)(B begin, E end, S step) if (is(typeof((E.init - B.init) + 1 * S.init))) { return Iota!(CommonType!(B, E), S)(begin, end, step); } I optimized things such that the commonly used path (many calls to empty, front, and popFront) is as fast as possible. The initial work will be amortized for most loops. On my machine, test4 is still 2x slower than foreach_reverse in an optimized build. The disassembly reveals that the compiler refuses to inline some calls, which is disappointing as their bodies are very simple. Andrei
Jun 21 2010
parent Brad Roberts <braddr puremagic.com> writes:
On 6/21/2010 8:12 PM, Andrei Alexandrescu wrote:
 
 I optimized things such that the commonly used path (many calls to
 empty, front, and popFront) is as fast as possible. The initial work
 will be amortized for most loops.
 
 On my machine, test4 is still 2x slower than foreach_reverse in an
 optimized build. The disassembly reveals that the compiler refuses to
 inline some calls, which is disappointing as their bodies are very simple.
 
 
 Andrei
If you would, file bugs with reduced tests and I'll work on the inliner.
Jun 21 2010
prev sibling next sibling parent reply BCS <none anon.com> writes:
On page 6 it say: "the code sample above also introduced the if statement" 
but none of them do. 

-- 
... <IXOYE><
Jun 21 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 10:01 PM, BCS wrote:
 On page 6 it say: "the code sample above also introduced the if
 statement" but none of them do.
Could you please add that to the errata? http://erdani.com/tdpl/errata Andrei
Jun 21 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

I optimized things such that the commonly used path (many calls to empty,
front, and popFront) is as fast as possible. The initial work will be amortized
for most loops.<
New timings: Running time, best of 3, seconds: test1: 0.31 test1 opt: 0.07 test2: 0.31 test2 opt: 0.12 test3: 6.38 test3 opt: 0.52 test3: 3.78 (new iota) test3 opt: 0.29 (new iota) test4: 4.70 test4 opt: 1.25 test4: 2.03 (new iota) test4 opt: 0.27 (new iota) Compile times opt version, seconds: test1: 0.05 test2: 0.05 test3: 0.28 test4: 0.23 (new iota) test4: 0.29 test4: 0.24 (new iota) (The difference in compile time between 0.29 and 0.23 is probably not significant. The difference between 0.05 and 0.23 is significant.) In my opinion the non-opt runtime timings too are important, because you can't compile code every time in opt mode. The normal for/foreach gives some performance even with no optmized compilation. It's good to optimize retro() so it can recognize the iota() argument and return just another iota().
On my machine, test4 is still 2x slower than foreach_reverse in an optimized
build.<
As you see on mine in an optimized build it's a bit slower than 2x than foreach_reverse and more than 4x slower than a normal for loop.
The disassembly reveals that the compiler refuses to inline some calls, which
is disappointing as their bodies are very simple.<
The code inside the loop here is very simple, it's just a variable (register) inc. In this case, in an optimized build GCC is able to optimize away the whole for loop. In my opinion a good D2 compiler has to to do the same with a foreach(retro(iota)) :-) If I am not wrong this is the inner loop of test4 with the new iota in opt build: L3F: mov ECX,018h[ESP] inc EBX add 010h[ESP],ECX mov EDX,010h[ESP] cmp EDX,014h[ESP] jne L3F It's not very good, but it's better than before. All those memory loads and stores are not necessary in this loop, they waste time. There is a call to this function, but it's before the call: _D3std5range13__T4IotaTiTiZ4Iota6__ctorMFNciiiZS3std5range13__T4IotaTiTiZ4Iota comdat L0: sub ESP,0Ch mov ECX,offset FLAT:_D3std5range13__T4IotaTiTiZ4Iota6__ctorMFNciiiZS3std5range13__T4IotaTiTiZ4Iota14__dgliteral607MFZAxa push EBX push EBP mov EBP,020h[ESP] push ESI mov ESI,EAX push EDI mov EDI,020h[ESP] test EDI,EDI mov 014h[ESP],EAX mov 018h[ESP],ECX je L28 cmp EBP,024h[ESP] jne L2C L28: xor EDX,EDX jmp short L31 L2C: mov EDX,1 L31: xor DL,1 je L5A push dword ptr FLAT:_DATA[054h] mov EDX,ECX push dword ptr FLAT:_DATA[050h] push 084Dh mov EAX,020h[ESP] mov EBX,020h[ESP] call EDX push EDX push EAX call near ptr _D3std9contracts7bailOutFAyaixAaZv L5A: test EDI,EDI mov [ESI],EBP mov 8[ESI],EDI jle L77 mov EDX,024h[ESP] dec EDX mov EAX,EDX mov 4[ESI],EDX sub EAX,EBP cdq idiv EDI sub 4[ESI],EDX jmp short L89 L77: mov ECX,024h[ESP] inc ECX mov EAX,ECX mov 4[ESI],ECX sub EAX,EBP cdq idiv EDI add 4[ESI],EDX L89: add 4[ESI],EDI mov EAX,ESI pop EDI pop ESI pop EBP pop EBX add ESP,0Ch ret 0Ch It's a lot of code, that's the iota constructor. The _D3std9contracts7bailOutFAyaixAaZv is probably the enforce or part of it. Doubling the loop size (N), the running time becomes about double, so such call to the constructor is not taking a lot of time (because there are no loops in the constructor). ------------------- I have seen that iota() contains: this(N current, N pastLast, S step) { enforce(step != 0 && current != pastLast); Indeed this throws: import std.range; void main() { int count; foreach (x; iota(10, 10, 1)) count++; } While his Python code gives no output:
 for x in xrange(10, 10, 1): print x
...

 for x in xrange(20, 10, 1): print x
... In my opinion an empty loop is a valid loop, just as this is valid both syntactically and logically: for (int i = 10; i < 10; i++) {} for (int i = 20; i < 10; i++) {} So I suggest to replace that line in the iota() costructor with: enforce(step != 0); And then create an empty generator if pastLast <= current (and the step is 1). Bye, bearophile
Jun 22 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/22/2010 07:18 AM, bearophile wrote:
 So I suggest to replace that line in the iota() costructor with:

 enforce(step != 0);

 And then create an empty generator if pastLast<= current (and the step is 1).
Absolutely. I wrote that test to simplify my life, but in the final version iota should accept empty ranges. Andrei
Jun 22 2010
prev sibling next sibling parent reply Byron Heads <wyverex.cypher gmail.com> writes:
On pg. 12 you define a recursive binary search, you forgot to pass value 
on the recursive call.

-B
Jun 22 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/22/2010 11:16 AM, Byron Heads wrote:
 On pg. 12 you define a recursive binary search, you forgot to pass value
 on the recursive call.

 -B
Saw the erratum you posted - thanks! Andrei
Jun 22 2010
prev sibling next sibling parent reply Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
Can someone sanity check me on the code on pages 334-5?

Does the method push really need !empty in its in contract?

I might not be fully awake yet ><

A...
Jun 24 2010
parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Alix Pexton wrote:

 Can someone sanity check me on the code on pages 334-5?
 
 Does the method push really need !empty in its in contract?
 
 I might not be fully awake yet ><
 
 A...
It has to be an error. If you couldn't push onto an empty stack, then you'd never be able to put anything on the stack. - Jonathan M Davis
Jun 24 2010
parent reply Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
On 24/06/2010 09:09, Jonathan M Davis wrote:
 Alix Pexton wrote:

 Can someone sanity check me on the code on pages 334-5?

 Does the method push really need !empty in its in contract?

 I might not be fully awake yet><

 A...
It has to be an error. If you couldn't push onto an empty stack, then you'd never be able to put anything on the stack. - Jonathan M Davis
That's what I thought, but it's there in the example over the page as well, so I though maybe I was missing something >< A...
Jun 24 2010
parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Alix Pexton wrote:

 On 24/06/2010 09:09, Jonathan M Davis wrote:
 Alix Pexton wrote:

 Can someone sanity check me on the code on pages 334-5?

 Does the method push really need !empty in its in contract?

 I might not be fully awake yet><

 A...
It has to be an error. If you couldn't push onto an empty stack, then you'd never be able to put anything on the stack. - Jonathan M Davis
That's what I thought, but it's there in the example over the page as well, so I though maybe I was missing something >< A...
I haven't look at it in detail yet, but it definitely looks like it's a copy-paste error, and it makes no sense for a push function to insist that something have already been pushed before you can push anything onto the stack. - Jonathan M Davis
Jun 24 2010
prev sibling parent Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
Does anyone else feel that the following is a fair clarification?

Page 396
...
	This means that communicating processors "forget" the exact order in 
which data was written: one tread writes x and then y and for a while 
another thread sees the new y but only the old x.

vvv

	This means that communicating processors "forget" the exact order in 
which data was written: one tread writes to x and then to y and for a 
while another thread sees the new value of y but only the old value of x.

...


Once I got my head around what is being claimed, I realised that it is 
correct as it appears, but it took me several reading to get there. It 
might just be because I'm a bit of a concurrency novice, but I'm sure 
I'm not the only one with a copy of tDPL ^^

A...
Jun 24 2010