Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

for loop off by 1 #18

Closed
chuckup opened this issue May 27, 2014 · 6 comments
Closed

for loop off by 1 #18

chuckup opened this issue May 27, 2014 · 6 comments

Comments

@chuckup
Copy link

chuckup commented May 27, 2014

With this code:

for n in range(5):
    print (n)

print ('n should be 4:', n)

I get this output:

0
1
2
3
4
"n should be 4:",5 

Rapydscript generates this code:

for (n = 0; n < 5; n++) {
    _$rapyd$_print(n);
}
_$rapyd$_print("n should be 4:", n);

It does not matter if I "include stdlib" or not.

But, everything works as expected if I do this:

for i, n in enumerate(range(5)):
    print (i, n)

print ('n should be 4:', n)

In this version, Rapydscript uses the stdlib range() function

@chuckup chuckup changed the title range() off by 1 for loop off by 1 May 27, 2014
@atsepkov
Copy link
Owner

The range function works fine, the example that reports different n than what you'd expect is a compile-time optimization RapydScript does to the logic. Technically it is a bug (I will fix it), but it's not the range function that is broken, what's happening is n gets incremented at the end of the loop, if the loop was rewritten as below, this bug could be avoided:

for (n = 0; n <= 5-1; n++) {
    _$rapyd$_print(n);
}

On a related note, it's a bad practice to use n outside of the loop after it terminates, the fact that it doesn't get reset is a side-effect of Python's scoping. RapydScript simply emulates that, pure JavaScript destroys the variable declared inside the loop when it's done.

@chuckup
Copy link
Author

chuckup commented May 27, 2014

pure JavaScript destroys the variable declared inside the loop when it's done.

Are you sure? I am new to javascript (in fact I have yet to write a line of it!) so I may be mistaken, but from what I've just read, javascript's scope is either global or by function, not by block. I have seen several stackoverflow answers that say this, and I also tried your example above in jsfiddle and I can still access n outside of the for loop - even if I stick a "var" in front of the "n=0" .

There is a new (since 2009?) "let" keyword that can do what you say, but it does not seem to me that the variable is destroyed unless you go out of your way to do so (with let keyword).

On a related note, it's a bad practice to use n outside of the loop after it terminates,

I am curious why you say that. What you said above ( for-loop scope ) is true in Lua, and that seemed like a wart to me. I agree it's bad to pollute the global namespace, but I don't see the harm in the way python keeps it around.

Lastly,

for (n = 0; n <= 5-1; n++) {
    _$rapyd$_print(n);
}

I tried your fixed example above, and it still has n = 5 after the for loop is completed.

Off topic, just wanted to say - I am very excited about Rapydscript - I have put off learning Javascript for nearly 20 years, turned off by the C-like syntax. Rapydscript "feels" right, without the bloat of the other python-in-browser projects - Thank you for writing it!

@atsepkov
Copy link
Owner

Yes, if the variable is properly declared inside the loop (as below), it will be destroyed:

for (var n in range(5)) {
    ...
}

If you forget var, then it will in fact be global, but that's not a proper declaration in JavaScript, these "features" that encourage JavaScript developers to shoot themselves in the foot is why alternatives such as CoffeeScript and RapydScript exist. You are correct that a variable declared within the loop body itself will be local to the containing function, not the loop, but the iterator declared in conditional will be local to the loop. Try the following, for example:

for (var n in [0,1,2,3,4]) {
    console.log(n);
}
console.log(n);

I just tested the example, and you're right that it doesn't fix it, I guess I was wrong about order of operations in the conditional check, I'll fix it by decrementing it at the end of the loop instead.

I'm glad you like RapydScript, that's exactly the same motivation I had for writing it, after playing with some of the more bloated alternatives. I encourage you to join our mailing list as well: https://groups.google.com/forum/?fromgroups#!forum/rapydscript

@chuckup
Copy link
Author

chuckup commented May 27, 2014

Yes, if the variable is properly declared inside the loop (as below), it will be destroyed:
...
the iterator declared in conditional will be local to the loop. Try the following, for example:

I did try this, see: http://jsfiddle.net/j22d4/

and n is still alive (not destroyed), so I am not sure what you mean...?

I will check out the mailing list! Thanks

@atsepkov
Copy link
Owner

You're right, I was testing it incorrectly.

@atsepkov
Copy link
Owner

Hmm, rather than fixing this I think I'll have the linter prevent this usage. Using loop-specific variables outside of a loop is poor design - and in fact not possible in many other languages including perl (and soon won't be possible in native JavaScript with the addition of let keyword). If you need to access the variable after the loop terminates, better technique is to copy the value to another variable before loop finishes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants