web-dev-qa-db-ja.com

ダックタイピングなしで動的に型付けされた言語を持つことは可能ですか?

この質問は尋ねられました ここ が、不十分な回答を受け取り、問題を明確にしませんでした。私はそれが再びそれを求めることを正当化すると信じています。

動的に型付けされた言語または静的に型付けされた言語のいずれかでダックタイピングができることを理解しています(ただし、C++のテンプレートなど、これらの例はまれです)。

しかし、動的に型付けされた言語なしのようなものがあるかどうかはわかりません。

ダックタイピングとは、オブジェクトのタイプが、ある時点でのオブジェクトの操作と属性に基づいていることを意味します。ダックタイピングを必然的にサポートせずに動的タイピングを行う方法はありますか?

このPythonコードの例を見てみましょう:

_def func(some_object)
    some_object.doSomething()

something = Toaster()
func(something)
_

動的型付け言語では、オブジェクトの型は実行時にのみ認識されます。したがって、それに対して操作を実行しようとすると(例:some_object.doSomething())、ランタイムには1つの選択肢しかありません-これはチェックすることです_some_object_の型がdoSomething()をサポートするかどうか。これは、正確にダックタイピングと同じです。

だから、ダックタイピングなしで動的に型付けされた言語を持つことは可能ですか?説明してください。

9
Aviv Cohn

まず、同じことを話していることを確認するために、いくつかの定義から始めます。

静的型付けは、コンパイル時に型エラーが報告されることを意味し、動的型付けは、実行時に型エラーが報告されることを意味します。

ダックタイピングは、コードが、オブジェクトが使用される操作のみをサポートすることを必要とすることを意味します。

構造タイピングでは、オブジェクトが特定の一連の操作をサポートしている必要があります(一部の操作が使用されていない場合でも)。

名義型付けは、オブジェクトが指定された型と完全に一致するか、その型のサブタイプである必要があります。

ご覧のとおり、構造型はアヒル型より厳密で、名義型は構造型より厳密です。

次に、 TypeScript言語 について説明します。これは、これらのオプションのほとんどを適切に示しているためです。

次のTypeScriptプログラムについて考えてみましょう。

interface Person {
    Name : string;
    Age : number;
}

function greet(person : Person) {
    alert("Hello, " + person.Name);
}

greet({ Name: "svick" });

greetに渡されるオブジェクトにはAgeプロパティがないため、これによりコンパイル時エラーが発生し、TypeScriptが静的構造型指定を使用していることが示されます

エラーにもかかわらず、上記のコードは実際には次のJavaScriptにコンパイルされ、正常に実行されます。

function greet(person) {
    alert("Hello, " + person.Name);
}

greet({ Name: "svick" });

これは、TypeScriptが動的ダックタイピングも使用することを示しています。

コードが代わりに次のようにコンパイルされた場合:

function greet(person) {
    if (!(typeof(person.Name) == 'string' && typeof(person.Age) == 'number'))
        throw 'TypeError';

    alert("Hello, " + person.Name);
}

これは、動的構造型付けの例になります。これは、関数自体が必要としない場合でも、オブジェクトが必要な型の必要なプロパティを持っていることを確認するためです。

コンパイルした場合:

function greet(person) {
    if (!(person instanceof Person))
        throw 'TypeError'

    alert("Hello, " + person.Name);
}

これは、動的名目タイピングの例です。これは、構造ではなくオブジェクトのタイプの名前をチェックするためです。

これがすべて示しているのは、動的な非アヒルのタイピングが可能であることです(構造的および公称の両方)。ただし、このアプローチはあまり使用されません。これは、非ダックタイピング(型を明示的に指定する必要がある、柔軟性が低い)と動的タイピング(型エラーは実行時にのみ表示され、実際に実行されるコードでのみ表示される)のデメリットをほとんど組み合わせているためです。 )。

型注釈を追加して非ダック型付けを可能にする場合は、コンパイル時に型を確認することもできます。

19
svick

どうやら(私が読んだものから) ダックタイピング は、関数がオブジェクトにメソッドとしてアタッチされている場合、オブジェクト指向のコンテキストでのみ意味があります。次に、duck.quacks(3)を記述するときに、duckの現在の値にメソッドquacksがある場合、これは機能します。

動的型付けは、必ずしもOOメソッドのあるビューに添付されているわけではありません。

タイプrealを関連する演算子または関数+: real*real->realで定義し、タイプrationalを関連する演算子+: rational*rational->rationalで定義できます。次に、動的にチェックされる時間システムでa+bを記述すると、変数abの両方に+演算子が含まれる可能性がありますが、実行時の型はエラー。

動的型付けでは、値のカテゴリの一貫性をチェックします。

ダックタイピングは、手元にあるオブジェクト(私が理解している限り、単一のオブジェクト)とコードの動作の一貫性をチェックします。

ある意味では、アヒルのタイピングは、単一のオブジェクトのアクセスメソッドにのみ適用されるという事実を除いて、ランタイムポリモーフィズムの形式です。

しかし、実行される演算子+がすべての引数に基づいて決定されるような、実行時のポリモーフィズムのより一般的な形式を定義することもできます。アヒルとニワトリが共通のダンス機能を共有している場合、一緒にダンスできるように。アヒルが別の機能を持つガチョウと一緒に踊ることができるように、彼らはいくつかを持つことができます。しかし、それは少し複雑に思えます。私が覚えている限りでは、オブジェクト指向言語の非常に古い先駆者である language EL1 の汎用関数を使用して、(おそらくより多くの構造を持つ)何かが可能だったかもしれません。

3
babou