ダイナミックバインディング

動的バインディング（）、遅延バインディング（）Booch, Grady. Object-oriented Analysis and Design. Addison-Wesley, 1994. p71あるいは動的リンケージ（）動的リンク（dynamic linking）とは異なる。は、コンピュータプログラミングにおいて、オブジェクトに対して呼ばれるメソッドあるいは引数を伴い呼び出される関数を、その名前に基づいて実行時に探索 (look up) するというメカニズムである。それぞれ動的束縛、遅延束縛、動的結合とも邦訳される。しかし、の意味でこれらの用語が使われることもあるLate Binding in Java - Stack Overflow。

対義語は静的バインディング（）あるいは事前バインディング（）であり、コンパイル時に確定する静的なオフセット情報などをもとにして関数実体のアドレスを取得する。

 概要 
静的型付けのプログラミング言語において、変数や式の型はコンパイル時に確定する。関数（メソッド）の存在確認は、コンパイル時にその名前（識別子）や引数リストの型、所属する名前空間および型などに基づいて事前に検査される。プログラマによって記述された関数呼び出しを、実際に関数が実装されているコードに一致させるプロセスのことをバインディングと呼ぶUse early binding and late binding in Automation - Office | Microsoft Docs。

C++やJavaといった静的型付けのオブジェクト指向言語では、オブジェクトの型に基づいて実際に呼び出される関数（メソッド）が実行時に選択される「仮想関数」（仮想メソッド）を使った動的ディスパッチ（）によりポリモーフィズムを実現する。コンパイル時には、所望の関数を呼び出すためのアドレス情報が（バイナリ）プログラム内に仮想関数テーブルにおけるメモリオフセットとして保持される。実行時に格納されたメモリオフセットすなわちアドレス情報（関数ポインタ）を使って所望の関数が呼び出される。この方式は、仮想関数テーブルの構造が事前に分かっているという点で、事前バインディングの一種である。

遅延バインディングでは、コンパイラは仮想関数テーブルに所望の仮想関数が存在するかどうかを確認するために十分な情報を読み取らず、代わりに名前を用いて実行時にルックアップする。Component Object Model (COM) プログラミングにおける遅延バインディングの主要な利点は、コンパイラがオブジェクトの型情報を含むライブラリ（DLL）を参照する必要がないということである。名前ベースの柔軟なプログラミングが可能となることで、ライブラリのバージョン衝突に対してコンパイル処理に耐性がもたらされる.NET - COMの機能を使用する – IJCAD ヘルプセンター。遅延バインディングのデメリットとして、実行時に名前解決を試みるために、統合開発環境によるコード補完などの支援や、コンパイル時の静的な型チェック機構が働かず、実行時になって初めてプログラミングミスが発覚する可能性が高くなること、またコンパイラ最適化が働かず、オーバーヘッドが大きくなり実行速度が低下することが挙げられる事前バインディングと遅延バインディング - Visual Basic | Microsoft Docs。

動的プログラミング言語のシンボル探索は基本的に名前ベースで、実行時に解決する動的バインディング方式である。ダック・タイピングも参照のこと。

 動的ディスパッチの例 
C++では以下のように仮想関数を派生クラスにてオーバーライドすることで、実際に呼び出される関数の実体をオブジェクトの型に応じて実行時に選択することができる。これを動的ディスパッチと呼ぶ。
#include <iostream>

class Base {
public:
    // 基底クラスにて virtual 指定を外すと、動的ディスパッチではなくなる。
    virtual void MemberFunc() {
        std::cout << "Base::MemberFunc() is called." << std::endl;
    }
};

class Derived : public Base {
public:
    // 派生クラスでの virtual 指定の有無は、オーバーライドとは無関係。
    // C++11 規格以降は override キーワードを後置することで、正しくオーバーライドされているかどうかコンパイラにチェックさせることもできる。
    virtual void MemberFunc() {
        std::cout << "Derived::MemberFunc() is called." << std::endl;
    }
};

// Base クラスから派生していない型のインスタンスを Base& で受け取ることはできない。コンパイラの静的な型チェックによりエラーとなる。
// つまり、MemberFunc() の存在有無は静的に検証される。
void CallMemberFunc(Base& obj) {
    obj.MemberFunc();
}

int main() {
    Base b;
    CallMemberFunc(b);
    Derived d;
    CallMemberFunc(d); // Base& で受け取って MemberFunc() を呼び出しているが、実際に呼ばれるのは Derived::MemberFunc() のほう。
}

仮想関数テーブルを利用した動的ディスパッチは、前述のように事前バインディングの一種であり、真の意味での動的バインディング／遅延バインディングとは異なる。しかし、動的ディスパッチの意味でこれらの用語が使われていることもある。

 遅延バインディングの例 
VB.NETにおける遅延バインディングの例を示す。
Option Strict Off

Class SomeClass1
    Public Sub SomeMethod
        Console.WriteLine("SomeClass1.SomeMethod() is called.")
    End Sub
End Class

Class SomeClass2
    Public Sub SomeMethod
        Console.WriteLine("SomeClass2.SomeMethod() is called.")
    End Sub
End Class

Public Class LateBindingExample
    Shared Sub CallSomeMethod(obj As Object)
        ' Option Strict On を指定するとコンパイルエラーになる。
        obj.SomeMethod()
    End Sub

    Shared Function Main As Integer
        CallSomeMethod(New SomeClass1())
        CallSomeMethod(New SomeClass2())
        Return 0
    End Function
End Class

VB.NETにおけるObject型は、.NETの基本クラス型System.ObjectObject Class (System) | Microsoft Docsであり、あらゆる型の最上位基底クラスであるが、Object型自体には上記のSomeMethodという名前を持つメソッドは定義されていない。しかし、Option Strict Offを指定することで、コンパイル時にメソッドの存在有無を確認しなくなり、実行時に探索を試みる。これが遅延バインディングである。もし該当メソッドが見つからなかった場合、実行時に例外System.MissingMemberExceptionがスローされる内部的にはVB.NETのコンパイラサービスによる遅延バインディング機能Microsoft.VisualBasic.CompilerServices.LateBindingが使用されている。。

なお、VB.NETのコンパイラでは、デフォルトでOption Strict Offとなっており、遅延バインディングが許可されている[Visual Basic の既定値] ([オプション] ダイアログ ボックス - [プロジェクト]) - Visual Studio (Windows) | Microsoft Docs。

JavaやC#ではリフレクションを使って遅延バインディングを実現することもできる。C# 4.0以降はdynamic型を使用した遅延バインディングも可能となっているdynamic 型の使用 - C# プログラミング ガイド | Microsoft Docs。Visual Basic .NET (VB.NET) ではOption Strict Offによって遅延バインディングが可能であるオブジェクト変数の宣言 - Visual Basic | Microsoft Docs。

Windows APIのGetProcAddress()GetProcAddress | Microsoft Docsや、POSIXのdlsym()dlsym | The Open Group Base Specifications Issue 7, 2018 edition | IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)は、関数名の文字列に基づいてモジュール内の関数ポインタを探索する。これらを使うことで、遅延バインディングを実現することもできる。

 脚注 

 注釈 

 出典 

 関連項目 
 動的プログラミング言語
 ダック・タイピング
 束縛 (コンピュータ)


Category:プログラミング言語の概念
Category:ソフトウェア工学