The following code snippets compare closures in several languages.
First is closure in javascript. Here I use nvm to run javascript code.
$ cat closure.js
function extent() {
var n = 0;
return function() {
n++;
console.log("n=" + n);
}
}
extent()();
extent()();
f = extent();
console.log("-----");
//console.log(extent.uniqueId());
f();
f();
$ nvm alias default 0.10
$ nvm run closure.js
Running node v0.10.30
n=1
n=1
-----
n=1
n=2
In above example, the closure is function() { n++; console.log... }
.
It's bound to variable "f". The local variable "n" is "closed" into closure.
Its lifetime is the same with "f".
So after the first execution of f, its inner state is saved.
For Python, nested function can only access variables in outer scope, but can't reassign (modify) them. So I use list as a workaround. In Python 3, there is a new keyword "nonlocal" to remove this restriction.
$ cat closure.py2.py
def extent():
n = [0]
def afun():
n[0] += 1
print('n=' + str(n[0]))
return afun
extent()()
extent()()
print('-----')
f = extent()
f()
f()
print("type of f is %s, its id is %d" % (type(f), id(f)))
$ python closure.py2.py
n=1
n=1
-----
n=1
n=2
type of f is <type 'function'>, its id is 140403684898408
$ cat closure.py3.py
def extent():
n = 0
def afun():
nonlocal n
n += 1
print('n=' + str(n))
return afun
extent()()
extent()()
f = extent()
print('----')
f()
f()
print("type of f is %s, its id is %d" % (type(f), id(f)))
[0] python3 closure.py3.py
n=1
n=1
----
n=1
n=2
type of f is <class 'function'>, its id is 139914425096528
The Ruby environment used here is RVM. Ruby version is 2.1.2.
$ rvm use 2.1.2 --default
$ cat closure.rb
def extent
n = 0
lambda {
n += 1
printf "n=%d\n", n
}
end
extent().call()
extent().call()
f = extent()
puts '------'
f.call()
f.call()
puts "class of f is #{f.class.name}, its id is #{f.object_id}"
$ ruby closure.rb
n=1
n=1
------
n=1
n=2
class of f is Proc, its id is 6724520
Two versions of Scala, define functions via "def" and "val" give different results:
$ diff *.scala
1c1
< def extent = {
---
> val extent = {
$ cat closure-def.scala
def extent = {
var n = 0
() => {
n += 1
println("n=" + n)
}
}
extent()
extent()
val f = extent
println("------")
f()
f()
println(s"Class of f is ${f.getClass}, its id is ${f.hashCode}")
$ scala closure-def.scala
n=1
n=1
------
n=1
n=2
Class of f is class Main$$anon$1$$anonfun$extent$1, its id is 8970973
$ cat closure-val.scala
val extent = {
var n = 0
() => {
n += 1
println("n=" + n)
}
}
extent()
extent()
val f = extent
println("------")
f()
f()
println(s"Class of f is ${f.getClass}, its id is ${f.hashCode}")
$ scala closure-val.scala
n=1
n=2
------
$ scala closure-val.scala
n=1
n=2
------
n=3
n=4
Class of f is class Main$$anon$1$$anonfun$1, its id is 8970973