var checkmate_depth # or may be defined global
for i in 0..Ply:
result = alphabeta(Black, i, -AB_Inf, AB_inf)
if result.score.abs > SureCheckmate:
checkmate_depth = i
break
Here the explicit assignment "checkmate_depth = i" is necessary to save that value because iteration variable is only locally valid. Of course I could use a while loop. But I may like something like
var checkmate_depth # or may be defined global
for checkmate_depth in 0..Ply:
result = alphabeta(Black, checkmate_depth, -AB_Inf, AB_inf)
if result.score.abs > SureCheckmate:
break
I am not sure how useful that may be, maybe a break in a for loop is a rare case, and maybe a local iteration variable is always faster.
Making the iteration variable visible at the outer scope would cause problems in the following scenario:
for i in 0..9:
discard
for i in 0..9: # redefinition of i
discard
There is also the question what the value of i would be upon successful completion of the loop (imagine iterating over an enum).
I think no problem in your example. If there is an i in outer scope, that is used for both loops. If not, then both loops use a locale i.
But indeed:
for i in 0..9:
for i in 0..9:
discard
would be a problem! So really a bad idea. (Indeed, I would not like the keyword for to work always for variables of outer scope, I had in mind more a special variant maybe with other name or marked somehow. But indeed, I think we do not need that, it would be useful only in rare cases.)
I note that this could be done by allowing for loops (and possible while loops) as expressions. In order for them to work correctly as expressions, they'd need something like the else clause in Python (which arguably should have been named differently) and break would have to work with expression arguments within them. Then you could write:
let checkmate_depth =
for i in 0..Ply:
result = alphabeta(Black, i, -AB_Inf, AB_inf)
if result.score.abs > SureCheckmate:
break i
else: -1 # or raise an error or whatever
I am not sure whether this is used frequently to justify the additional complexity, but it would be a solution. I also note that one could write a template to accomplish the same, e.g.:
template loopWithDefault(default: typed, body: untyped): untyped =
block:
var `.result` = default
template exit(val: type(default)) =
`.result` = val
break
body
`.result`
let checkmate_depth = loopWithDefault(-1) do:
for i in 0..Ply:
result = alphabeta(Black, i, -AB_Inf, AB_inf)
if result.score.abs > SureCheckmate:
exit i
P.S. loopWithDefault should be coded so that the default isn't evaluated unless loop falls through.
@jibal: I think you misunderstood something. This is not to get souped-up loop behavior, the only reason for the else clause to exist would be just so that the expression is well-defined even if the loop terminates normally. As I said, I'm not even sure that the extra complexity can be justified without even including any additional Perl craziness.
As for the template not always evaluating the default, sure. I wrote this up as a quick hack, not as a serious proposal.
I think you misunderstood something.
I'm pretty sure I didn't. I was simply pointing out that Perl6 achieves what Python's else: does with the LAST block, which is part of a general language mechanism -- the main point was that Python isn't the only language with syntax to support this sort of loop. Of course one need not adopt the whole mechanism (what you pejoratively call "craziness") in order to get the functionality of else: or loopWithDefault, but there is some value to orthogonality. The other Perl6 property blocks offer all the functionality of the C for loop, in a more general (but more verbose) way. But that's Perl6, and I'm not proposing to add such things to Nim, just mentioning how another language does it, just as you mentioned how Python does it.
just so that the expression is well-defined
Not quite. Your own post notes # or raise an error or whatever. The reality is that there are arbitrary possibilities for the the termination action. As I noted, one way to achieve this without any language change or macro is to put the loop into a function and return instead of break.
As for the template not always evaluating the default, sure. I wrote this up as a quick hack, not as a serious proposal.
And I simply noted a problem with that specific implementation ... one that could bite someone if they just copied it ... which people often do. Years from now you might see it in some code and say "but I wrote that up as a quick hack, not as a serious proposal".