Last active
October 25, 2016 00:45
-
-
Save sigriston/09fb0fa908f9319402b2d211d6e0c94a to your computer and use it in GitHub Desktop.
Closures - JavaScript vs. Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
let funcs = [] | |
for (let i = 0; i < 4; i++) { | |
funcs.push(x => x * i) | |
} | |
console.log(funcs[0](10)) // prints '0' | |
console.log(funcs[1](10)) // prints '10' | |
console.log(funcs[2](10)) // prints '20' | |
console.log(funcs[3](10)) // prints '30' | |
// If you're a JavaScript programmer, the results above look pretty obvious. | |
// However, if you're a Python programmer with no familiarity with JavaScript, | |
// the results might have been a little surprising. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
funcs = [] | |
for i in range(4): | |
funcs.append(lambda x: x * i) | |
print(funcs[0](10)) # prints '30' | |
print(funcs[1](10)) # prints '30' | |
print(funcs[2](10)) # prints '30' | |
print(funcs[3](10)) # prints '30' | |
# If you're a knowledgeable Python developer, the results above are expected. | |
# However, if you are a JavaScript dev who mostly dabbles in Python here and | |
# there, you must have freaked out at this point. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Rust, however, allows for both styles of closures, allowing you to get the | |
// same results as either Python or JavaScript depending on what you need. | |
use std::cell::Cell; | |
fn python_closure<'a>() { | |
let ic = Cell::new(0); | |
type PythonClosure<'a> = Box<Fn(i32) -> i32 + 'a>; | |
let mut funcs: Vec<PythonClosure> = Vec::new(); | |
for i in 0..4 { | |
ic.set(i); | |
// Closures in Python have what Rust calls "borrow semantics", taking | |
// references to local variables in its environment. | |
funcs.push(Box::new(|x| x * ic.get())); | |
} | |
println!("{}", (*funcs[0])(10)); // prints "30" | |
println!("{}", (*funcs[1])(10)); // prints "30" | |
println!("{}", (*funcs[2])(10)); // prints "30" | |
println!("{}", (*funcs[3])(10)); // prints "30" | |
} | |
fn js_closure() { | |
type JSClosure = Box<Fn(i32) -> i32>; | |
let mut funcs: Vec<JSClosure> = Vec::new(); | |
for i in 0..4 { | |
// Closures in JavaScript have what Rust calls "move semantics", where | |
// the closure gets a copy of values in its environment at the time the | |
// closure is defined. | |
funcs.push(Box::new(move |x| x * i)); | |
} | |
println!("{}", (*funcs[0])(10)); // prints "0" | |
println!("{}", (*funcs[1])(10)); // prints "10" | |
println!("{}", (*funcs[2])(10)); // prints "20" | |
println!("{}", (*funcs[3])(10)); // prints "30" | |
} | |
pub fn main() { | |
println!("Python-style closures:"); | |
python_closure(); | |
println!("JavaScript-style closures:"); | |
js_closure(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@NiltonVolpato Yeah, that is a way!
In my production code though, what I really wanted to do was effectively a partial, so I ended up using just
functools.partial
.