Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Closure (computer programming)
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== Differences in semantics == === Lexical environment === As different languages do not always have a common definition of the lexical environment, their definitions of closure may vary also. The commonly held minimalist definition of the lexical environment defines it as a set of all [[Name binding|bindings of variables]] in the scope, and that is also what closures in any language have to capture. However the meaning of a [[Variable (programming)|variable]] binding also differs. In imperative languages, variables bind to relative locations in memory that can store values. Although the relative location of a binding does not change at runtime, the value in the bound location can. In such languages, since closure captures the binding, any operation on the variable, whether done from the closure or not, are performed on the same relative memory location. This is often called capturing the variable "by reference". Here is an example illustrating the concept in [[ECMAScript]], which is one such language: <syntaxhighlight lang="javascript"> // Javascript var f, g; function foo() { var x; f = function() { return ++x; }; g = function() { return --x; }; x = 1; alert('inside foo, call to f(): ' + f()); } foo(); // 2 alert('call to g(): ' + g()); // 1 (--x) alert('call to g(): ' + g()); // 0 (--x) alert('call to f(): ' + f()); // 1 (++x) alert('call to f(): ' + f()); // 2 (++x) </syntaxhighlight> Function <code>foo</code> and the closures referred to by variables <code>f</code> and <code>g</code> all use the same relative memory location signified by local variable <code>x</code>. In some instances the above behaviour may be undesirable, and it is necessary to bind a different lexical closure. Again in ECMAScript, this would be done using the <code>Function.bind()</code>. ===Example 1: Reference to an unbound variable=== <ref>{{cite web |title=Function.prototype.bind() |url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind |website=MDN Web Docs |access-date=20 November 2018}}</ref> <syntaxhighlight lang="javascript"> var module = { x: 42, getX: function() {return this.x; } } var unboundGetX = module.getX; console.log(unboundGetX()); // The function gets invoked at the global scope // emits undefined as 'x' is not specified in global scope. var boundGetX = unboundGetX.bind(module); // specify object module as the closure console.log(boundGetX()); // emits 42 </syntaxhighlight> ===Example 2: Accidental reference to a bound variable=== For this example the expected behaviour would be that each link should emit its id when clicked; but because the variable 'e' is bound to the scope above, and lazy evaluated on click, what actually happens is that each on click event emits the id of the last element in 'elements' bound at the end of the for loop.<ref>{{cite web |title=Closures |url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake |website=MDN Web Docs |access-date=20 November 2018}}</ref> <syntaxhighlight lang="javascript"> var elements = document.getElementsByTagName('a'); // Incorrect: e is bound to the function containing the 'for' loop, not the closure of "handle" for (var e of elements) { e.onclick = function handle() { alert(e.id); } } </syntaxhighlight> Again here variable <code>e</code> would need to be bound by the scope of the block using <code>handle.bind(this)</code> or the <code>let</code> keyword. On the other hand, many functional languages, such as [[ML (programming language)|ML]], bind variables directly to values. In this case, since there is no way to change the value of the variable once it is bound, there is no need to share the state between closures—they just use the same values. This is often called capturing the variable "by value". Java's local and anonymous classes also fall into this category—they require captured local variables to be <code>final</code>, which also means there is no need to share state. Some languages enable choosing between capturing the value of a variable or its location. For example, in C++11, captured variables are either declared with <code>[&]</code>, which means captured by reference, or with <code>[=]</code>, which means captured by value. Yet another subset, [[lazy evaluation|lazy]] functional languages such as [[Haskell]], bind variables to results of future computations rather than values. Consider this example in Haskell: <syntaxhighlight lang="haskell"> -- Haskell foo :: Fractional a => a -> a -> (a -> a) foo x y = (\z -> z + r) where r = x / y f :: Fractional a => a -> a f = foo 1 0 main = print (f 123) </syntaxhighlight> The binding of <code>r</code> captured by the closure defined within function <code>foo</code> is to the computation <code>(x / y)</code>—which in this case results in division by zero. However, since it is the computation that is captured, and not the value, the error only manifests when the closure is invoked, and then attempts to use the captured binding. === Closure leaving === Yet more differences manifest themselves in the behavior of other lexically scoped constructs, such as <code>return</code>, <code>break</code> and <code>continue</code> statements. Such constructs can, in general, be considered in terms of invoking an [[escape continuation]] established by an enclosing control statement (in case of <code>break</code> and <code>continue</code>, such interpretation requires looping constructs to be considered in terms of recursive function calls). In some languages, such as ECMAScript, <code>return</code> refers to the continuation established by the closure lexically innermost with respect to the statement—thus, a <code>return</code> within a closure transfers control to the code that called it. However, in [[Smalltalk]], the superficially similar operator <code>^</code> invokes the escape continuation established for the method invocation, ignoring the escape continuations of any intervening nested closures. The escape continuation of a particular closure can only be invoked in Smalltalk implicitly by reaching the end of the closure's code. These examples in ECMAScript and Smalltalk highlight the difference: <syntaxhighlight lang="smalltalk"> "Smalltalk" foo | xs | xs := #(1 2 3 4). xs do: [:x | ^x]. ^0 bar Transcript show: (self foo printString) "prints 1" </syntaxhighlight> <syntaxhighlight lang="javascript"> // ECMAScript function foo() { var xs = [1, 2, 3, 4]; xs.forEach(function (x) { return x; }); return 0; } alert(foo()); // prints 0 </syntaxhighlight> The above code snippets will behave differently because the Smalltalk <code>^</code> operator and the JavaScript <code>return</code> operator are not analogous. In the ECMAScript example, <code>return x</code> will leave the inner closure to begin a new iteration of the <code>forEach</code> loop, whereas in the Smalltalk example, <code>^x</code> will abort the loop and return from the method <code>foo</code>. [[Common Lisp]] provides a construct that can express either of the above actions: Lisp <code>(return-from foo x)</code> behaves as [[Smalltalk]] <code>^x</code>, while Lisp <code>(return-from nil x)</code> behaves as [[JavaScript]] <code>return x</code>. Hence, Smalltalk makes it possible for a captured escape continuation to outlive the extent in which it can be successfully invoked. Consider: <syntaxhighlight lang="smalltalk"> "Smalltalk" foo ^[ :x | ^x ] bar | f | f := self foo. f value: 123 "error!" </syntaxhighlight> When the closure returned by the method <code>foo</code> is invoked, it attempts to return a value from the invocation of <code>foo</code> that created the closure. Since that call has already returned and the Smalltalk method invocation model does not follow the [[spaghetti stack]] discipline to facilitate multiple returns, this operation results in an error. Some languages, such as [[Ruby (programming language)|Ruby]], enable the programmer to choose the way <code>return</code> is captured. An example in Ruby: <syntaxhighlight lang="ruby"> # Ruby # Closure using a Proc def foo f = Proc.new { return "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" end # Closure using a lambda def bar f = lambda { return "return from lambda" } f.call # control does not leave bar here return "return from bar" end puts foo # prints "return from foo from inside proc" puts bar # prints "return from bar" </syntaxhighlight> Both <code>Proc.new</code> and <code>lambda</code> in this example are ways to create a closure, but semantics of the closures thus created are different with respect to the <code>return</code> statement. In [[Scheme (programming language)|Scheme]], definition and scope of the <code>return</code> control statement is explicit (and only arbitrarily named 'return' for the sake of the example). The following is a direct translation of the Ruby sample. <syntaxhighlight lang="Scheme"> ; Scheme (define call/cc call-with-current-continuation) (define (foo) (call/cc (lambda (return) (define (f) (return "return from foo from inside proc")) (f) ; control leaves foo here (return "return from foo")))) (define (bar) (call/cc (lambda (return) (define (f) (call/cc (lambda (return) (return "return from lambda")))) (f) ; control does not leave bar here (return "return from bar")))) (display (foo)) ; prints "return from foo from inside proc" (newline) (display (bar)) ; prints "return from bar" </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)