クロージャ

クロージャを持つプログラミング言語

Schemeは完全な静的スコープのクロージャを持つ最初の言語として登場した。Common Lispはそれを取り入れた。実質的にすべての関数型言語（Scala、Haskell、OCamlなど）とSmalltalkに由来するオブジェクト指向言語は何らかの形でクロージャを持っている。
クラスを使用するオブジェクト指向言語では、完全なクロージャになるにはメソッドの中でクラス定義できることが必要だが、メソッドあるいは関数の中でラムダ式／無名関数が使え、その中から外のローカル変数を読み書きできれば、一般的にはそのプログラミング言語はクロージャを使えるとみなされる。よって、クロージャを持つ言語には、C#（3.0以降）、C++（C++11以降）、ECMAScript（JavaScriptを含む）、Groovy、Java（8以降）、Perl、Python、Ruby、PHP（5.3以降）、Lua、Squirrelなどがある。
セマンティクスはそれぞれ大きく異なっているが、多くの現代的な汎用のプログラミング言語は静的スコープとクロージャのいくつかのバリエーションを持っている。

セマンティクスの違い

言語ごとにスコープのセマンティクスが異なるように、クロージャの定義も異なっている。汎用的な定義では、クロージャが捕捉する「環境」とは、あるスコープのすべての変数の束縛の集合である。しかし、この変数の束縛というものの意味も言語ごとに異なっている。命令型言語では、変数は値を格納するためのメモリ中の位置と束縛される。この束縛は変化せず、束縛された位置にある値が変化する。クロージャは束縛を捕捉しているので、そのような言語での変数への操作は、それがクロージャからであってもなくとも、同一のメモリ領域に対して実行される。例として、ECMAScriptを取り上げると
var f, g;function foo(){
  var x = 0;
  f = function() { ++x; };
  g = function() { --x; };
  x = 1;
  print(f()); // "2"}foo();g(); // "1"f(); // "2"
関数 foo と2つのクロージャがローカル変数 x に束縛された同一のメモリ領域を使用していることに注意。
一方、多くの関数型言語、例えばML、は変数を直接、値に束縛する。この場合、一度束縛された変数の値を変える方法はないので、クロージャ間で状態を共有する必要はない。単に同じ値を使うだけである。
さらに、Haskellや、Common Lisp上に作られたCLAZYパッケージ(言語拡張)など、遅延評価を行う関数型言語では、変数は将来の計算結果に束縛される。例を挙げる。
foo x y = let r = x / y
          in (\z -> z + r)f = foo 1 0main = do putStr (show (f 123))
r は計算 (x / y) に束縛されており、この場合は0による除算である。しかしながら、クロージャが参照しているのはその値ではなく計算であるので、エラーはクロージャが実行され、実際にその束縛を使おうと試みたときに現れる。
さらなる違いは静的スコープである制御構文、C言語風の言語における return・break・continue などにおいて現れる。ECMAScriptなどの言語では、これらはクロージャ毎に束縛され、構文上の束縛を隠蔽する。つまり、クロージャ内からの return はクロージャを呼び出したコードに制御を渡す。しかしSmalltalkでは、このような動作はトップレベルでしか起こらず、クロージャに捕捉される。例を示して、この違いを明らかにする。
"Smalltalk"foo
  | xs |
  xs := #(1 2 3 4).
  xs do: [:x | ^x].
  ^0bar
  Transcript show: (self foo) "prints 1"
// ECMAScriptfunction foo() {
  var xs = new Array(1, 2, 3, 4);
  xs.forEach(function(x) { return x; });
  return 0;}print(foo()); // prints 0
Smalltalkにおける ^ はECMAScriptにおける return にあたるものだと頭に入れれば、一目見た限りではどちらのコードも同じことをするように見える。違いは、ECMAScriptの例では return はクロージャを抜けるが関数 foo は抜けず、Smalltalkの例では ^ はクロージャだけではなくメソッド foo をも抜ける、という点である。後者の特徴はより高い表現力をもたらす。Smalltalkの do: は通常のメソッドであり、自然に制御構文が定義できている。一方、ECMAScriptでは return の意味が変わってしまうので、同じ目的には foreach という新しい構文を導入しなければならない。
しかし、スコープを越えて生存する継続には問題もある。
foo
  ^[ x: | ^x ]
bar
  | f |
  f := self foo.
  f value: 123 "error!"
上の例でメソッド foo が返すブロックが実行されたとき、foo から値を返そうとする。しかし、foo の呼び出しは既に完了しているので、この操作はエラーとなる。

Ruby

Rubyなどの言語では、プログラマが return の振る舞いを選ぶことができる。
def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo"end
  
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"
この例の Proc.new と lambda はどちらもクロージャを作るための方法である。しかし、それぞれが作ったクロージャの return の振る舞いに関しては、異なるセマンティクスを持っている。

Common Lisp

Common Lispにおいては、すべての関数、クロージャ、無名関数などは最終的にアセンブリ言語に似たtagbodyに展開されると考えてよい。原理的にはすべてのプログラムは機械語へコンパイルまたはインタープリットされるはずなので、他の言語においてもこの発想は自然である。tagbodyは内部でgo命令によってタグにジャンプすることができる。これも、直接的にアセンブリのラベル及びJMP命令と対応させられる。
関数はタグ(名前)付きのブロックであり、クロージャ、無名関数などは無名のブロックをもつ。無名ブロックの名前はnilとなる。この仕様の下で、Common Lispにはreturnおよびreturn-fromが用意されている。(return 0)は(return-from nil 0)と同値であり、すなわち一番近いブロックから抜け出すことを意味する。従って、どのような状況下でも、ブロックの名前を指定して任意の場所から脱出することができる。以下に例を示す。
(defun a (x)
  (* 3 
     (block b
       (* 100
          (funcall (lambda (y)
                     (cond
                       ((= 0 (mod y 3)) (return-from a y))       ; 3の倍数にはaから値をそのまま返す
                       ((oddp y)        (return-from b (* 2 y))) ; 奇数には二倍してbまで脱出
                       (otherwise       (return y))))            ; どちらでもなければlambdaからyを返す
                   x)))))(a 1);--> 6(a 2);--> 600(a 3);--> 3

C++

C++11規格以降でラムダ式が使えるようになった。なお、以下のようにローカル変数のキャプチャの方法を制御することができる。詳細はC++11を参照。
#include <iostream>#include <vector>#include <string>#include <algorithm>void foo(std::string s) {
    int n = 0;
    // すべての自由変数をコピーキャプチャ。
    auto func1 = [=]() { std::cout << n << ", " << s << std::endl; };
    n = 1;
    s = "";
    func1();
    // すべての自由変数を参照キャプチャ。
    auto func2 = [&]() { n = -1; s = "hoge"; };
    func2();
    std::cout << n << ", " << s << std::endl;}bool findName(const std::vector<std::string>& v, const std::string& name) {
    // 名前を指定して自由変数を参照キャプチャ。
    auto it = std::find_if(v.begin(), v.end(), [&name](const std::string& s) { return s == name; });
    return it != v.end();}

C

C言語では、コールバックをサポートするライブラリ関数の中に、以下のように関数へのポインタと付随する任意のデータを指すためのポインタ（例えば汎用ポインタであるvoid*など）という2つの値を受け取るものがある。
typedef int CallbackFunctionType(void* userData);extern int callUserFunction(CallbackFunctionType* callbackFunction, void* userData);
ライブラリ関数callUserFunctionがコールバック関数callbackFunctionを実行するたび、実行コンテキストとしてデータポインタuserDataを使用する。これによってコールバックは状態を管理することができ、登録した任意の情報を参照できる。このイディオムはクロージャと機能面で似ているが、構文面では似ていない。

C++

C++では、operator() をオーバーロードしたクラス（あるいは構造体）により、関数オブジェクトを定義できる。これは関数型言語における関数にいくらか似た振る舞いをみせる。C++の関数オブジェクトは非静的メンバー変数により状態を持つこともできる。しかし、一般的なクロージャのように自動的に（暗黙的に）ローカル変数を捕捉（キャプチャ）するようなことはしない。
また、ローカルクラス、すなわち関数内でクラスを定義することも可能だが、C++11よりも前の規格（C++03以前）ではテンプレート型引数として渡すことができなかったり、暗黙的に参照できる外のローカル変数は static 変数のみであり、自由変数のキャプチャを模倣するためには関数オブジェクトの非静的メンバー変数として明示的に保存しておく必要があったりするなど、後述する Java の無名クラス以上に制約条件が多い。C++11以降のラムダ式は、内部的にはコンパイラによる関数オブジェクトの自動生成により実現されている。したがって、自由変数をキャプチャする際には、関数オブジェクトであってもラムダ式であっても、変数寿命に配慮する必要がある。

Eiffel

Eiffelにはクロージャを定義するためのinline agent（インラインエージェント）がある。インラインエージェントはルーチンを表すオブジェクトで、次のように利用する。
OK_button.click_event.subscribe(
    agent(x, y: INTEGER) do
        country := map.country_at_coordinates(x, y)
        country.display
    end)
subscribe の実引数はインラインエージェントで、2つの引数を持つ手続きである。ユーザがこのボタンをクリックして、click_event タイプのイベントが起こると、マウスの座標を引数としてこの手続きが実行される。
Eiffelのインラインエージェントの大きな限界は、外側のスコープのローカル変数を参照できないという点である。

Java 7 以前

Java 7 以前では、メソッド内部に「無名クラス」を定義することで似たようなことができる。無名クラスからは、そのメソッドの final （リードオンリー）なローカル変数を、無名クラスのメンバ変数と名前が被らない限り、参照できる。
class CalculationWindow extends JFrame {
    private JButton saveButton;
    ...

    public final void calculateInSeparateThread(final URI uri) {
        // The expression "new Runnable() { ... }" is an anonymous class.
        Runnable runner = new Runnable() {
            void run() {
                // It can access final local variables:
                calculate(uri);
                // It can access private fields of the enclosing class:
                // Always update the Graphic components into the Swing Thread
                SwingUtilities.invokeLater(new Runnable() {
                     public void run() {
                         saveButton.setEnabled(true);
                     }
                });                   
            }
        };
        new Thread(runner).start();
    }}
要素が1つの配列を final な参照で保持すれば、クロージャで1つのローカル変数を参照する機能をエミュレートできる。内部クラスはその参照の値そのものを変えることはできないが、参照されている配列の要素の値は変えることができるからである。このテクニックはJavaに限ったものではなく、Pythonなど似た制限を持つ言語でも有効である。
Javaに完全なクロージャを追加するという言語拡張が検討されていた。様々な問題により、クロージャを導入せずに、SAM Typeなインターフェース実装の簡単な表記法が Java 8 にて導入された。