Skip to content

Instantly share code, notes, and snippets.

@myw
Last active August 29, 2015 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myw/178165ff5002915e0ad3 to your computer and use it in GitHub Desktop.
Save myw/178165ff5002915e0ad3 to your computer and use it in GitHub Desktop.
Examples of function scoping in python, C, and JavaScript
#include <stdio.h>
int func(int, int, int);
int
main()
{
printf("%d\n", func(3, 4, 5));
return 0;
}
int
func(int a, int b, int c)
{
int d, h;
d = 7;
h = 3;
while (h < 5) {
int d = 1;
h++;
d++;
}
return d;
}
#include <stdio.h>
int func(int, int, int);
int
main()
{
printf("%d\n", func(3, 4, 5));
return 0;
}
int
func(int a, int b, int c)
{
int d, h;
d = 7;
h = 3;
while (h < 5) {
d = 1;
h++;
d++;
}
return d;
}
function func(a, b, c) {
var d, h;
d = 7;
h = 3;
while (h < 5) {
var d = 1;
h++;
d++;
}
return d;
}
function main() {
console.log(func(3, 4, 5));
}
if (require.main === module) {
main();
}
function func(a, b, c) {
var d, h;
d = 7;
h = 3;
while (h < 5) {
d = 1;
h++;
d++;
}
return d;
}
function main() {
console.log(func(3, 4, 5));
}
if (require.main === module) {
main();
}
def func(a, b, c):
d = 7
h = 3
while h < 5:
d = 1
h += 1
d += 1
return d
if __name__ == '__main__':
print(func(3, 4, 5))
@mmachenry
Copy link

The Python example might seem intuitive in this short program but can be terribly confusing. It depends on what you intended. The problem is that there's no difference syntactically between variable assignment and declaration. If you intended variable assignment then you got it right. But if when you wrote "d=1" you were thinking "Make a new variable called d and initialize it to 1" then you have a bug. In most languages, including Scheme, Perl when use strict is on, Java, and ML these are two distinct operations. Furthermore with a good environment you'll get a warning for shadowing the declaration of d, but it's not an error.

In the Javascript version of this code it's absolutely insidious because Javascript has an explicit declaration with 'var' but they outright lie to you and just turn that into assignment.

(define (func1 a b c)
  (let ([d 7]
        [h 3])
    (let while ()
      (let ([d 1])
        (set! h (+ h 1))
        (set! d (+ d 1)))
      (when (< h 5) (while)))
    d))

(= (func1 3 4 5) 7)

(define (func2 a b c)
  (let ([d 7]
        [h 3])
    (let while ()
      (set! d 1)
      (set! h (+ h 1))
      (set! d (+ d 1))
      (when (< h 5) (while)))
    d))

(= (func2 3 4 5) 2)

@myw
Copy link
Author

myw commented Aug 5, 2015

yes, exactly

@mmachenry
Copy link

Another way to look at it is through the idea of referential transparency. When does this snippet of code do it you put it in the middle of your program?

a = 1
b = 2
if a < b:
    temp = a
    a = b
    b = temp

A lot of people would expect it to have just the effect of assigning a=2 and b=1 but it has the additional, perhaps unexpected, effect of assigning temp, should it already exist, to 1. In Scheme, this code looks like this:

(let ([a 1
      [b 2])
  (when (< a b)
      (let ([temp a])
          (set! a b)
          (set! b temp))))

If there is a temp in scope outside of this block of code it has the exact same effect. temp is just briefly shadowed because the developer who added this code probably didn't know about it, but she doesn't have to because the lexical scoping makes it clear what this code is doing regardless of any, potentially hairy, context it might be in.

This is all solved by introducing a let or my or var keyword. Personally I'd require it. I hear this is happening in Python 3. I'm not sure if it's going to change it's scoping though. I'll have to read up on that. Hopefully the introduction of this keyword doesn't work like var in Javascript.

@myw
Copy link
Author

myw commented Aug 12, 2015

There are no scoping changes planned for Py3 as far as I can tell. ECMAScript 6, however, is planning on adding a let keyword, which would work normally, unlike that insane var nonsense: all curly braces would create local scope for variables declared with let.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment