アーリーバインディングとレイトバインディングは何ですか?


77

アーリーバインディングとレイトバインディングについてよく耳にしますが、それらが何であるかはわかりません。私は理解できない次の説明を見つけました:

アーリーバインディングとは、設計時に変数に値を割り当てることを指し、レイトバインディングとは、実行時に変数に値を割り当てることを指します。

誰かが2つのタイプのバインディングを定義して比較できますか?


1
コンパイル時間とランタイム。
barlop

以下は、このテーマに関する良い読み物です。en.wikibooks.org
ジェイエルストン

回答:


84

混乱には、バインディングとロードの2つの主要な概念があります。これは、DataBindingの概念によって混同されます。DataBindingは、中間のどこかで両方を頻繁に実行します。それを検討した後、もう1つの概念を追加して、三連符を完成させます。

タイプ

遅延バインディング:実行時に変数が実行されるまで、タイプは不明です。通常は割り当てによってですが、型を強制する他の手段があります。動的に型付けされた言語はこれを基礎となる機能と呼びますが、多くの静的に型付けされた言語には遅延バインディングを実現する何らかの方法があります

多くの場合、[特別な]動的型、イントロスペクション/リフレクション、フラグ、コンパイラオプションを使用して、または動的ディスパッチの借用と拡張による仮想メソッドを介して実装されます。

アーリーバインディング:実行時に変数が実行される前に、通常は静的な宣言的手段によって型が認識さます

標準のプリミティブ型を使用して頻繁に実装されます

機能

静的ディスパッチ:コンパイル時の既知の特定の関数またはサブルーチン。明確であり、署名と一致する

静的関数として実装されます。同じ署名を持つメソッドはありません

動的ディスパッチ:コンパイル時の特定の関数またはサブルーチンではありません。実行中にコンテキストによって決定されます。「動的ディスパッチ」には、適切な関数実装を選択するために使用されるコンテキスト情報によって区別される2つの異なるアプローチがあります。

[ 動的 ] ディスパッチ、インスタンスの唯一の種類は、適切な機能の実装を決定するために使用されます。静的に型付けされた言語では、これが実際に意味することは、変数が宣言/割り当てられたときに示された参照型に関係なく、インスタンス型がどのメソッド実装を使用するかを決定することです。適切な実装を推測するために単一のタイプ(オブジェクトインスタンスのタイプ)のみが使用されるため、このアプローチは「単一ディスパッチ」と呼ばれます。

また、複数の [ dynamic ] ディスパッチがあります。ここで、入力パラメーターのタイプは、呼び出す関数実装の決定にも役立ちます。インスタンスのタイプパラメーターのタイプの両方である複数のタイプが、どのメソッド実装が選択されるかに影響するため、このアプローチは「複数ディスパッチ」と呼ばれます。

仮想関数または抽象関数として実装されます。他の手がかりには、オーバーライド、非表示、またはシャドウメソッドが含まれます。

注意: メソッドのオーバーロードに動的ディスパッチが含まれるかどうかは、言語固有です。 たとえば、Javaでは、オーバーロードされたメソッドは静的にディスパッチされます。

遅延読み込み必要になるまで値の割り当て延期するオブジェクト初期化戦略。オブジェクトを本質的に有効ですが、故意に不完全な状態にし、データがロードされる前にデータが必要になるまで待機することを許可します。大規模なデータセットのロードや外部リソースの待機に特に役立つことがよくあります

多くの場合、コンストラクターまたは初期化の呼び出し中に、下流の呼び出し元がそのコレクションのコンテンツ(get_value_at、get_all_asなど)を確認するまで、コレクションまたはリストを意図的に複合オブジェクトにロードしないことによって実装されます。バリエーションには、コレクションに関するメタ情報(サイズやキーなど)の読み込みが含まれますが、実際のデータは省略されます。また、いくつかのランタイムにメカニズムを提供し、開発者にかなり安全で効率的なシングルトン実装スキームを提供します

Eager Loading:自身が有効な状態にあるとみなす前にすべてのデータを完了する必要があるために、すべての値の割り当てすぐに実行するオブジェクト初期化戦略。

コンストラクターの呼び出しや初期化中など、できるだけ早くすべての既知のデータを複合オブジェクトに提供することにより、しばしば実装されます

データバインディング:多くの場合、2つの互換性のある情報ストリーム間にアクティブなリンクまたはマップを作成し、一方への変更が他方に反映されるようにします。互換性を持たせるために、多くの場合、共通のベースタイプまたはインターフェイスが必要です。

さまざまなアプリケーションの側面(ビューからモデルへのビュー、モデルからコントローラーへなど)とソースとターゲット、エンドポイント、バインド/バインド解除、更新、およびイベントなどの概念についてのよりクリーンで一貫した同期を提供する試みとしてしばしば実装されますon_bind、on_property_change、on_explicit、on_out_of_scope


編集メモ:これらの頻繁な発生の例の説明を提供する最後の主要な編集。特定のコード例は、実装/ランタイム/プラットフォームに完全に依存します


2
この答えは、オブジェクト指向言語に固有のものです。
ジャック

27

コンパイル中にコンパイラによって決定されるものはすべて、EARLY / COMPILE TIME Bindingを参照でき、RUNTIMEで決定されるものはすべてLATE / RUNTIMEバインディングと呼ばれます。

例えば、

メソッドのオーバーロードとメソッドのオーバーライド

1)メソッドのオーバーロードでは、メソッドへのメソッド呼び出しは、どの関数が呼び出されるかがコンパイラーによってコンパイル時に決定されるという意味で、コンパイラーによって決定されます。したがって、初期のバインドです。

2)メソッドのオーバーライドでは、RUNTIMEでどのメソッドが呼び出されるかが決定されます。そのため、LATE BINDINGと呼ばれます。

シンプルで簡単に入手できるようにしました。お役に立てれば。


9

遅延バインディングは、実行時に動作が評価されるときです。プログラムが実行されているときにのみ持っている情報に基づいて行動する方法を実際に決定したい場合に必要です。私の意見で最も明確な例は、特にC ++の仮想関数メカニズムです。

class A
{
public:
    void f() {}
    virtual void g() {}
};

class B : public A
{
    void f() {}
    virtual void g() {}
};

int main()
{
    A* a = new B;
    a->f();
    a->g();
}

この例では、a->f()実際に呼び出します。void A::f()それは、早期(または静的)バインドされ、その実行時にプログラムだから、考えて、それはちょうどポインタだAのに対し、型変数a->g()実際に呼び出しますvoid B::g()コンパイラは、シーイングがあるため、g()仮想で、検索するコードを挿入実行時に呼び出す正しい関数のアドレスを設定します。


1
「ランタイム」?あなたはC ++について話している。C ++はマシンコードに直接コンパイルされるため、仮想メソッドを解決するためのランタイムは必要ありません。
tdammers

3
@tdammers C ++は実際にはランタイムライブラリを必要としますが、仮想呼び出しは必要ありません。あなたが慎重に読めば、あなたはこの答えは、コンパイラが言っていることに気づくでしょう「正しい機能[...]のアドレスをルックアップするためのコードを挿入ランタイム」。

しかし、その「正しい関数のアドレスを検索するためのコード」は、基本的には、型にとらわれない2段階のポインター逆参照とそれに続く関数呼び出しです。関係する「思考」はありません。確実に動作する唯一の理由は、コンパイラがコンパイル時に型チェックを行うためです。実行時に、生成されたコードはコンパイラが型チェックの宿題を行ったことを信頼します。安全でないキャスト(Cスタイルポインターキャストなど)を使用する場合、C ++オブジェクトを間違ったクラスのオブジェクトとして合法的に扱うことができます、それらのvtableは完全に台無しになり、コードが壊れます。
-tdammers

@tdammers私はその種の答えから離れようとしました。なぜなら、それはコンパイラの実装の詳細であり、ある難解なコンパイラには当てはまるかもしれないし、当てはまらないかもしれないからです。重要なのはコンセプトです。
ヤムマルコビッチ

1
@tdammersそして「ランタイム」とは、「実行時のプログラム」を意味します。明らかにC ++は管理されていません。しかし、あなたはそれが混乱を引き起こす可能性があることを示したので、私はそれを完全な言葉遣いに変えています。
ヤムマルコビッチ

5

関数ポインタに精通している場合、これは例になります。定義された関数は、Early bindingと呼ばれます。一方、関数ポインターを使用する場合、その遅いバインディング。

  int add(int x,int y)
  {
    return x+y;
  }
  int sub(int x,int y)
  {
      return x-y;
  }


    int main()
    {
     //get user choice
     int(*fp)(int,int);
     //if add
      fp=add;
     //else if sub
     fp=sub;
     cout<<fp(2,2);
    }

ここで、関数addおよびsubは関数です(そのアドレスはコンパイル時にリンカーにバインドされます)

ただし、関数ポインターはレイトバインディングであり、fpは[実行時]ユーザーの選択に応じてaddまたはsubを呼び出すことができます。


3

アーリーバインディングとレイトバインディングは、型のコンテキストでのみ意味があり、それを記述する方法では意味がありません。ほとんどすべての現代言語は、すべての値が固定型であるという意味で型付けされています。動的に型付けされた言語と静的に型付けされた言語を比較すると違いが生じます。動的に型付けされた言語では、変数は型を持たないため、任意の型の値を参照できます。つまり、変数によって参照されるオブジェクトのメソッドを呼び出すとき、その呼び出しが有効かどうかを判断する唯一の方法はオブジェクトのクラスを検索し、そのメソッドが実際に存在するかどうかを確認します。実際のメソッド検索は最後の瞬間まで延期されるため、これにより、実行時にクラスに新しいメソッドを追加するようなクールなことが可能になります。ほとんどの人はこの状態をレイトバインディングと呼びます。

静的に型付けされた言語では、変数は型を持ち、一度宣言されると、同じ型ではない値を参照できません。これは厳密には真実ではありませんが、今のところ仮定してみましょう。変数が特定の型の値のみを参照することがわかっている場合、コードが実行される前に有効性を判断できるため、メソッド呼び出しが実行時に有効かどうかを判断する理由はありません。これは、事前バインディングと呼ばれます。

rubyの遅延バインディングを示す例:

a = 1 # a is an integer at this point
a.succ # asking for its successor is valid

class A
  def method_a
    # some code
  end
end

a = A.new
a.method_a # this is also valid
a.succ # this is not valid


class A # we can re-open the class and add a method
  def succ
    # some more code
  end
end
a.succ # now this is valid

上記の一連のアクションは、実行時にすべてのタイプが固定されているJavaのような言語では不可能です。


1

アカデミックな定義を提供する代わりに、VBAを使用した実際の例を使用して、いくつかの違いを示します。

早期バインディング:

Dim x As FileSystemObject
Set x = New FileSystemObject
Debug.Print x.GetSpecialFolder(0)

これには、設計時に「Microsoft Scripting Runtime」コンポーネントへの参照を設定する必要があります。タイプミスFileSystemObjectやのようなメソッド名がある場合、コンパイル時にすでにエラーメッセージが表示されるという利点がありますGetSpecialFolder

遅延バインディング

Dim x As Object
Set x = CreateObject("Scripting.FileSystemObject")
Debug.Print x.GetSpecialFolder(0)

事前に参照を設定する必要はありません。インスタンスの作成とタイプの決定は実行時に行われます。コンパイラは、の存在しないメソッドを呼び出そうとすると、コンパイル時に文句を言いませんx。これにより、特定の行が実行された場合にのみ、ランタイムエラーが発生します。

したがって、遅延バインディングの欠点は、ここで強力な型チェックを行わないことです。しかし、それも利点です-たとえば、複数のバージョンが存在するコンポーネントがあり、それぞれの新しいバージョンがいくつかの追加機能を提供するとします。(実際の例は、Excel COMインターフェイスなどのMS Officeコンポーネントです)遅延バインディングを使用すると、そのすべてのバージョンで動作するコードを記述できます-最初に特定のコンポーネントのバージョンを特定できます。古いバージョンのみが使用可能です。そのバージョンでは機能しない関数呼び出しを実行しないでください。


-2

おそらく、遅延バインディングの最も一般的な例は、インターネットURLの解決です。到達する前に世界中のすべてのサイトをリンクおよびバインドしようとせずに動的システムと大規模システムをサポートしますが、一方で、実行時にオーバーヘッド(DNSルックアップ、はるかに少ないIPルーティング)が発生します。

そのことから、言語環境でのほとんどの種類のバインディングは、コンパイル時またはリンク時に多かれ少なかれ早くなります。

種類ごとにコストと利点があります。


このバインディングの定義の参照先を見つけることができますか?インターネットアドレスを「バインディング」として解決することを聞いたことはありませんが、バインディングは名前を解決する行為であるため、インターネットアドレスへのURIの解決にアーリー/レイトバインディングの概念を適用できると主張した人がいると思います。しかし、これは一般的な解釈ではなく、アーリー/レイトバインディングの概念は、コンピューターが一般的にインターネットに接続されていた時代よりも前のことです。
ジェイエルストン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.