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!
== Closure-like constructs == Some languages have features which simulate the behavior of closures. In languages such as [[C++]], [[C Sharp (programming language)|C#]], [[D (programming language)|D]], [[Java (programming language)|Java]], [[Objective-C]], and [[Visual Basic (.NET)]] (VB.NET), these features are the result of the language's object-oriented paradigm. === Callbacks (C) === Some [[C (programming language)|C]] libraries support [[Callback (computer programming)|callbacks]]. This is sometimes implemented by providing two values when registering the callback with the library: a function pointer and a separate <code>void*</code> pointer to arbitrary data of the user's choice. When the library executes the callback function, it passes along the data pointer. This enables the callback to maintain state and to refer to information captured at the time it was registered with the library. The idiom is similar to closures in functionality, but not in syntax. The <code>void*</code> pointer is not [[Type safety|type safe]] so this C idiom differs from type-safe closures in C#, Haskell or ML. Callbacks are used extensively in [[graphical user interface]] (GUI) [[widget toolkit]]s to implement [[event-driven programming]] by associating general functions of graphical widgets (menus, buttons, check boxes, sliders, spinners, etc.) with application-specific functions implementing the specific desired behavior for the application. ====Nested function and function pointer (C)==== With a [[GNU Compiler Collection]] (GCC) extension, a nested function<ref>{{cite web |url = https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html |title = Nested functions}}</ref> can be used and a function pointer can emulate closures, provided the function does not exit the containing scope. The next example is invalid because <code>adder</code> is a top-level definition (depending on compiler version, it could produce a correct result if compiled with no optimizing, i.e., at <code>-O0</code>): <syntaxhighlight lang="c"> #include <stdio.h> typedef int (*fn_int_to_int)(int); // type of function int->int fn_int_to_int adder(int number) { int add (int value) { return value + number; } return &add; // & operator is optional here because the name of a function in C is a pointer pointing on itself } int main(void) { fn_int_to_int add10 = adder(10); printf("%d\n", add10(1)); return 0; } </syntaxhighlight> But moving <code>adder</code> (and, optionally, the <code>typedef</code>) in <code>main</code> makes it valid: <syntaxhighlight lang="c"> #include <stdio.h> int main(void) { typedef int (*fn_int_to_int)(int); // type of function int->int fn_int_to_int adder(int number) { int add (int value) { return value + number; } return add; } fn_int_to_int add10 = adder(10); printf("%d\n", add10(1)); return 0; } </syntaxhighlight> If executed this now prints <code>11</code> as expected. === Local classes and lambda functions (Java) === [[Java (programming language)|Java]] enables [[class (object-oriented programming)|classes]] to be defined inside [[method (object-oriented programming)|methods]]. These are called ''local classes''. When such classes are not named, they are known as ''[[anonymous class]]es'' (or anonymous ''inner'' classes). A local class (either named or anonymous) may refer to names in lexically enclosing classes, or read-only variables (marked as <code>final</code>) in the lexically enclosing method. <syntaxhighlight lang="java"> class CalculationWindow extends JFrame { private volatile int result; // ... public void calculateInSeparateThread(final URI uri) { // The expression "new Runnable() { ... }" is an anonymous class implementing the 'Runnable' interface. new Thread( new Runnable() { void run() { // It can read final local variables: calculate(uri); // It can access private fields of the enclosing class: result = result + 10; } } ).start(); } } </syntaxhighlight> The capturing of <code>final</code> variables enables capturing variables by value. Even if the variable to capture is non-<code>final</code>, it can always be copied to a temporary <code>final</code> variable just before the class. Capturing of variables by reference can be emulated by using a <code>final</code> reference to a mutable container, for example, a one-element array. The local class will not be able to change the value of the container reference, but it will be able to change the contents of the container. With the advent of Java 8's lambda expressions,<ref>{{cite web |url=http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html |title=Lambda Expressions |work=The Java Tutorials}}</ref> the closure causes the above code to be executed as: <syntaxhighlight lang="java"> class CalculationWindow extends JFrame { private volatile int result; // ... public void calculateInSeparateThread(final URI uri) { // The code () -> { /* code */ } is a closure. new Thread(() -> { calculate(uri); result = result + 10; }).start(); } } </syntaxhighlight> Local classes are one of the types of [[inner class]] that are declared within the body of a method. Java also supports inner classes that are declared as ''non-static members'' of an enclosing class.<ref> {{cite web |url=https://blogs.oracle.com/darcy/entry/nested_inner_member_and_top |title=Nested, Inner, Member, and Top-Level Classes |work=Joseph D. Darcy's Oracle Weblog |date=July 2007|archive-url=https://web.archive.org/web/20160831172734/https://blogs.oracle.com/darcy/entry/nested_inner_member_and_top |archive-date=31 August 2016 }}</ref> They are normally referred to just as "inner classes".<ref> {{cite web |url=https://java.sun.com/docs/books/tutorial/java/javaOO/innerclasses.html |title=Inner Class Example |work=The Java Tutorials: Learning the Java Language: Classes and Objects }}</ref> These are defined in the body of the enclosing class and have full access to instance variables of the enclosing class. Due to their binding to these instance variables, an inner class may only be instantiated with an explicit binding to an instance of the enclosing class using a special syntax.<ref> {{cite web |url=https://java.sun.com/docs/books/tutorial/java/javaOO/nested.html |title=Nested Classes |work=The Java Tutorials: Learning the Java Language: Classes and Objects }}</ref> <syntaxhighlight lang="java"> public class EnclosingClass { /* Define the inner class */ public class InnerClass { public int incrementAndReturnCounter() { return counter++; } } private int counter; { counter = 0; } public int getCounter() { return counter; } public static void main(String[] args) { EnclosingClass enclosingClassInstance = new EnclosingClass(); /* Instantiate the inner class, with binding to the instance */ EnclosingClass.InnerClass innerClassInstance = enclosingClassInstance.new InnerClass(); for (int i = enclosingClassInstance.getCounter(); (i = innerClassInstance.incrementAndReturnCounter()) < 10; /* increment step omitted */) { System.out.println(i); } } } </syntaxhighlight> Upon execution, this will print the integers from 0 to 9. Beware to not confuse this type of class with the nested class, which is declared in the same way with an accompanied usage of the "static" modifier; those have not the desired effect but are instead just classes with no special binding defined in an enclosing class. As of [[Java version history#Java_8|Java 8]], Java supports functions as first class objects. Lambda expressions of this form are considered of type <code>Function<T,U></code> with T being the domain and U the image type. The expression can be called with its <code>.apply(T t)</code> method, but not with a standard method call. <syntaxhighlight lang="java"> public static void main(String[] args) { Function<String, Integer> length = s -> s.length(); System.out.println( length.apply("Hello, world!") ); // Will print 13. } </syntaxhighlight> === Blocks (C, C++, Objective-C 2.0) === {{Main|Blocks (C language extension)}} [[Apple Inc.|Apple]] introduced [[Blocks (C language extension)|blocks]], a form of closure, as a nonstandard extension into [[C (programming language)|C]], [[C++]], [[Objective-C 2.0]] and in [[Mac OS X Snow Leopard|Mac OS X 10.6 "Snow Leopard"]] and [[iOS 4]].0. Apple made their implementation available for the GCC and clang compilers. Pointers to block and block literals are marked with <code>^</code>. Normal local variables are captured by value when the block is created, and are read-only inside the block. Variables to be captured by reference are marked with <code>__block</code>. Blocks that need to persist outside of the scope they are created in may need to be copied.<ref>{{cite web |url=https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html |title=Blocks Programming Topics |author=<!-- Unstated staff writer --> |date=8 March 2011 |publisher=Apple Inc. |access-date=2011-03-08}}</ref><ref>{{cite web |url=http://thirdcog.eu/pwcblocks/ |title=Programming with C Blocks on Apple Devices |last=Bengtsson |first=Joachim |date=7 July 2010|access-date=2010-09-18|archive-url=https://web.archive.org/web/20101025034928/http://thirdcog.eu/pwcblocks/|archive-date=25 October 2010|url-status=dead}}</ref> <syntaxhighlight lang="objc"> typedef int (^IntBlock)(); IntBlock downCounter(int start) { __block int i = start; return [[ ^int() { return i--; } copy] autorelease]; } IntBlock f = downCounter(5); NSLog(@"%d", f()); NSLog(@"%d", f()); NSLog(@"%d", f()); </syntaxhighlight> === Delegates (C#, VB.NET, D) === [[C Sharp (programming language)|C#]] anonymous methods and lambda expressions support closure: <syntaxhighlight lang="csharp"> var data = new[] {1, 2, 3, 4}; var multiplier = 2; var result = data.Select(x => x * multiplier); </syntaxhighlight> [[Visual Basic .NET]], which has many language features similar to those of C#, also supports lambda expressions with closures: <syntaxhighlight lang="vb.net"> Dim data = {1, 2, 3, 4} Dim multiplier = 2 Dim result = data.Select(Function(x) x * multiplier) </syntaxhighlight> In [[D (programming language)|D]], closures are implemented by delegates, a function pointer paired with a context pointer (e.g. a class instance, or a stack frame on the heap in the case of closures). <syntaxhighlight lang="D"> auto test1() { int a = 7; return delegate() { return a + 3; }; // anonymous delegate construction } auto test2() { int a = 20; int foo() { return a + 5; } // inner function return &foo; // other way to construct delegate } void bar() { auto dg = test1(); dg(); // =10 // ok, test1.a is in a closure and still exists dg = test2(); dg(); // =25 // ok, test2.a is in a closure and still exists } </syntaxhighlight> D version 1, has limited closure support. For example, the above code will not work correctly, because the variable a is on the stack, and after returning from test(), it is no longer valid to use it (most probably calling foo via dg(), will return a 'random' integer). This can be solved by explicitly allocating the variable 'a' on heap, or using structs or class to store all needed closed variables and construct a delegate from a method implementing the same code. Closures can be passed to other functions, as long as they are only used while the referenced values are still valid (for example calling another function with a closure as a callback parameter), and are useful for writing generic data processing code, so this limitation, in practice, is often not an issue. This limitation was fixed in D version 2 - the variable 'a' will be automatically allocated on the heap because it is used in the inner function, and a delegate of that function can escape the current scope (via assignment to dg or return). Any other local variables (or arguments) that are not referenced by delegates or that are only referenced by delegates that do not escape the current scope, remain on the stack, which is simpler and faster than heap allocation. The same is true for inner's class methods that reference a function's variables. === Function objects (C++) === [[C++]] enables defining [[function object]]s by overloading <code>operator()</code>. These objects behave somewhat like functions in a functional programming language. They may be created at runtime and may contain state, but they do not implicitly capture local variables as closures do. As of [[C++11|the 2011 revision]], the C++ language also supports closures, which are a type of function object constructed automatically from a special language construct called ''lambda-expression''. A C++ closure may capture its context either by storing copies of the accessed variables as members of the closure object or by reference. In the latter case, if the closure object escapes the scope of a referenced object, invoking its <code>operator()</code> causes undefined behavior since C++ closures do not extend the lifetime of their context.{{main|Examples_of_anonymous_functions#C++_(since_C++11)}} <syntaxhighlight lang="cpp"> void foo(string myname) { int y; vector<string> n; // ... auto i = std::find_if(n.begin(), n.end(), // this is the lambda expression: [&](const string& s) { return s != myname && s.size() > y; } ); // 'i' is now either 'n.end()' or points to the first string in 'n' // which is not equal to 'myname' and whose length is greater than 'y' } </syntaxhighlight> === Inline agents (Eiffel) === [[Eiffel (programming language)|Eiffel]] includes inline agents defining closures. An inline agent is an object representing a routine, defined by giving the code of the routine in-line. For example, in <syntaxhighlight lang="eiffel"> ok_button.click_event.subscribe ( agent (x, y: INTEGER) do map.country_at_coordinates (x, y).display end ) </syntaxhighlight> the argument to <code>subscribe</code> is an agent, representing a procedure with two arguments; the procedure finds the country at the corresponding coordinates and displays it. The whole agent is "subscribed" to the event type <code>click_event</code> for a certain button, so that whenever an instance of the event type occurs on that button β because a user has clicked the button β the procedure will be executed with the mouse coordinates being passed as arguments for <code>x</code> and <code>y</code>. The main limitation of Eiffel agents, which distinguishes them from closures in other languages, is that they cannot reference local variables from the enclosing scope. This design decision helps in avoiding ambiguity when talking about a local variable value in a closure - should it be the latest value of the variable or the value captured when the agent is created? Only <code>Current</code> (a reference to current object, analogous to <code>this</code> in Java), its features, and arguments of the agent can be accessed from within the agent body. The values of the outer local variables can be passed by providing additional closed operands to the agent. === C++Builder __closure reserved word === Embarcadero C++Builder provides the reserved word <code>__closure</code> to provide a pointer to a method with a similar syntax to a function pointer.<ref>Full documentation can be found at http://docwiki.embarcadero.com/RADStudio/Rio/en/Closure</ref> Standard C allows writing a {{mono|[[typedef]]}} for a pointer to a [[function type]] using the following syntax:<syntaxhighlight lang="c++"> typedef void (*TMyFunctionPointer)( void ); </syntaxhighlight>In a similar way, a {{mono|typedef}} can be declared for a pointer to a method using this syntax:<syntaxhighlight lang="c++"> typedef void (__closure *TMyMethodPointer)(); </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)