sgzwiz / brython

Automatically exported from code.google.com/p/brython
BSD 3-Clause "New" or "Revised" License
0 stars 1 forks source link

Default arguments not properly bound at definition time #44

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
The following code:
l = []

for i in [1, 2]:
    def f(x=i):
        print(x)

    l.append(f)

l[0]()
l[1]() 

Outputs:
2
2

Instead of:
1
2

Original issue reported on code.google.com by pedro.ro...@gmail.com on 11 Jan 2013 at 9:26

GoogleCodeExporter commented 9 years ago
I don't think it's a bug in Brython not binding properly the variable, it's 
because Javascript overrides function definitions in a "for" loop. Take this 
example in Javascript :

<=============
funcs = []
for(var i=1;i<3;i++){
    function g(){}
    g.ident = i
    funcs.push(g)
}
console.log(funcs[0].ident)
console.log(funcs[1].ident) 
===============>
the result is :
2
2

There are techniques in Javascript 
(http://james.padolsey.com/javascript/closures-in-javascript/) but I don't see 
a way to implement them in Brython

Until someone finds a solution this should be mentioned as a difference between 
Brython and Python. I tag the issue "WontFix", tell me if you think it should 
be left open

Original comment by pierre.q...@gmail.com on 12 Jan 2013 at 10:55

GoogleCodeExporter commented 9 years ago
I think closure is important and so I would prefer to keep the topic open.

After seeing the first lines of the reference you gave, I modified your example:
funcs = []
for(var i=1;i<3;i++){
    g = function (){} // <--- here
    g.ident = i
    funcs.push(g)
}
console.log(funcs[0].ident)
console.log(funcs[1].ident)

And this gave the expected result.
By looking at the generated code by Brython, you should probably "create" a 
function
in that context and see if the same generation technique is also suitable for
"toplevel" function and methods.

Still there is the issue of the loop variable. For basic types bool, int, 
"immutable" strings, things should probably work easily. So I am wondering
what happends if you are iterating on an array of objects or lists.
does g.ident = i bind a reference to the object iterated, in which case I think
it shall ease the process of having better closure.

By the way, I notice that Brython functions are not "setattr"-able. 

Original comment by pedro.ro...@gmail.com on 12 Jan 2013 at 11:59

GoogleCodeExporter commented 9 years ago
Given the last comment which shows that this, in theory, can work using pure 
Javascript, how about using the equivalent of what is done for classes in py2js:

                }else if($funcs[parent][0]=='class'){
                    var class_name = $funcs[parent][1]
                    // replace "function foo" by "this.foo = function"
                    stack.list.splice(kw_pos,2,["code",'this.'+fname+'='],
                        ['keyword','function'])

to replace  "function fname"  by "fname = function" for functions definitions.

This may leave a small potential problem of a missing semi-colon at the end of 
the function definition.  As I understand
function foo() {...}
does not need a semi-colon; however
foo = function() {...};
does require one (I think).

Original comment by andre.ro...@gmail.com on 23 Jan 2013 at 3:14

GoogleCodeExporter commented 9 years ago
Thanks for the suggestion : replacing "function foo()" by "foo=function()" 
actually solves the problem
It will be fixed in the rewriting of the core modules

Original comment by pierre.q...@gmail.com on 14 Feb 2013 at 7:12

GoogleCodeExporter commented 9 years ago
Fixed in version 1.1

Original comment by pierre.q...@gmail.com on 16 Feb 2013 at 5:27