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


9

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

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

しかし、ダックタイピングのない動的に型付けされた言語のようなものがあるかどうかはわかりません。

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

たとえば、このPythonコードを見てみましょう。

def func(some_object)
    some_object.doSomething()

something = Toaster()
func(something)

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

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


1
私はWikipediaでいくつかの言語(Javascript、Ruby、PHP)を確認しましたが、後者は動的で弱いものであり、アヒル型ではありません。それはあなたの質問に答えるかもしれません。
Trylks 2014年

実際、ランタイムには、オブジェクトのフィールドへのアクセスやメソッドの呼び出しを行う前に、オブジェクトの型シグネチャをチェックする選択肢があります。それは「強力な動的型付け」です。たとえば、Pythonは部分的にこのように動作していることに注意してください。たとえば、試行すると明示的に型エラーが発行されます1 + "1"。Pythonの場合、チェックの原則はほとんどなく、ユーザー(Pythonのランタイムではなく)が有用であると判断した場合にタイプをチェックするかどうかは、ユーザーコードの実装次第です。また、ダックタイピングと非ダックタイピングは、名義型vs構造型タイピングと似ています(Wikipediaを参照)。
Michael Pankov 2014年

多分あなたはあなたのためにあなたのタイピングをするためにアヒルの代わりにガチョウを使うべきですか?
2014年

回答:


19

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

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

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

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

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

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

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

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

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

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

greet({ Name: "svick" });

渡されたオブジェクトにgreetAgeプロパティがないため、これによりコンパイル時エラーが発生し、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);
}

これは、構造ではなくオブジェクトの型の名前をチェックするため、動的な名目型付けの例です。

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

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


1
typescriptが動的なダックタイピングを使用しているとは言えません。コンパイルエラーにもかかわらず、tscがjavascriptを生成するという事実は私には奇妙に聞こえますが、とにかく...入力エラーはコンパイル時に報告され、ランタイム部分はtypescriptではなくjavascriptに残されます。ただし、typescriptは静的なダックタイピングも使用します。「var t = 1;」と記述した場合、変数は数値と見なされます。
Joel

@Joelはい、TypeScriptはJavaScriptから動的ダックタイピングを継承しますが、それでもTypeScriptのプロパティにはなりません。そして、あなたの例はダックタイピングではなくタイプ推論を示しています。
2014年

メソッドをインターフェイスの一部として定義する必要があるが、インターフェイスの任意の組み合わせを使用して格納場所を入力できる言語を何と呼びますか?合格した場合[3,4]1つの収集保持するいくつかの方法に[1,2]利回り[1,2,3,4]、および合格[3,4]保持一部にいくつかのコレクションの方法を[1,2]だろう[4,6]、この方法は、同じ名前を持つ必要がありますか?最初Sequence$Appendable$Addと2番目を呼び出すNumericVector$Addが、変数をa Sequenceまたはa として解釈する必要があると言うことができるNumericVector...
supercat

...ホモグラフィック名が混乱を引き起こさないことを単に望んでいるよりもきれいに見える。各変数が1つの型のみである必要がある言語では、「完全に動的な」型が役立つ場合がありますが、複合型が利用可能であれば、「異常な」アヒルの使用例の99%を排除できると思いますタイピング。
スーパーキャット2014年

@Joelに同意する傾向があります。警告と例外の違いは、言語の入力とはほとんど関係がありません。TypeScriptはライブラリです。tscそれへのインターフェースです。ライブラリを使用すると、イベントがトリガーされます。デフォルトでは、何も聞いていない場合はスクリプトを取得します。リスニングして例外をスローすると、スクリプトの生成を停止できます。TypeScriptの型システムは変わりますか?もちろん違います。
エヴァンキャロル

3

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

動的型付けは、必ずしもメソッドを使用してオブジェクト指向ビューに関連付けられるとは限りません。

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

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

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

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

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


Pythonは演算子のオーバーロードもサポートしています。def add(a、b):a + bを返すことができます。自動的にa .__ add __(b)に変換されます。...そうです、アヒルのタイピングには、ある種の高度なユーザー定義タイプが必要なようです。データメンバーも機能しますが、次のようにduck構造体も可能です:def addstuff(a、b、t):t.stuff = a.stuff + b.stuff
StarWeaver

@StarWeaverそうですね。しかし、あなたの例で私を悩ませているのは、オペランド間の非対称性です。型エラーがある場合は、aに適切なメソッドがないか、aのメソッドとbの型の間に型の不一致があるためです。したがって、状況に応じて、異なる例外が発生します(Pythonの私の記憶が正しい場合)。aとbを一緒に+できないという例外を受け取るだけのレベルの抽象化が必要な場合があります(奇妙な文では申し訳ありません)。しかし、それは好みの問題かもしれません。+は可換であると述べることもできます。
babou 2014年

-2

類推による答え:

あなたはコンバーチブルを購入して、トップを決して下に置くことができませんか?承知しました。一部の機能(たとえば、コンバーチブルトップ、構造要素としての屋根の欠如による追加の構造補強)に追加料金が支払われ、さらに悪い結果(たとえば、余分なロードノイズ、おそらく低いクラッシュの安全性、小さな収納コンパートメント)使用しない機能に投資した結果。しかし、それは技術的に実現可能です。

動的言語やダックタイピングでも同じです。静的言語のより高い効率とコンパイル時の型安全性の保証をあきらめました。何のために?一般的には、アヒルのタイピングを簡単にするためです。変数とコレクションは何でも保持でき、何を指定するだけで事前に多くのことを行う必要はありません。[ 12, "gumbo", 12.4, 4+4j ](整数、文字列、浮動小数点値、複素数値など)の混合コレクションは取るに足らないものであり、Javaコード(たとえば)に見られるような定数型キャストはありません。

Pythonのような動的言語では、アヒル型ではないオブジェクトを作成することが可能です。

class Hungarian(object):
    self __init__(self):
        self.value = []
    self addInt(self, intValue):
        self.value.append(intValue)
    self addFloat(self, floatValue):
        self.value.append(floatValue)
    self addComplex(self, complexValue):
        self.value.append(complexValue)
    # ...

ただし、お気づきかもしれませんが、型のチェックは実際には行われていません。各メソッドは、duck型の組み込み構造(list)を使用して実装されています。ダイナミズムの代償を払ったので、トップを下げて、結果としてシンプルになるでしょう:

class NotHungarian(object):
    def __init__(self):
        self.value = []
    def add(self, whatever):
        self.value.append(whatever)

そのHungarianクラスはアヒル型ではないのですか?ご指摘のとおり、型のチェックはありません。
2014年

@svickこれは、Javaなどのタイプ固有の方法で使用することを目的としており、実行されるアクションだけでなく、使用されるタイプにも依存する個別のメソッドがあります。アヒルのタイピングは、追加されるタイプに関係なく、同じ方法を使用NotHungarianします。ダックタイピングは、タイプをチェックしないことだけでなく、同じ呼び出し/メソッド/メッセージ名(add)を使用することにも依存します。(NotHungarianメソッド名も使用addsetます。これは、などの他のPythonオブジェクトと共通です。これは、他のオブジェクト/クラスと同様に「クック」します。)
Jonathan Eunice

1
この答えは、「静的言語のより高い効率とコンパイル時のタイプセーフティの保証をあきらめる」という動機について少し誤解されています。動機は、FortranまたはCのような型システムの束縛を手放すことでした。これらのシステムはしばしば邪魔になり(Pascalの固定長文字列を考えると)、一般的なプログラミングを妨げ、eval実行不可能などの非常に強力な機能を作成します。動機は決して型を取り除くことではなく、一部の動的言語には「段階的な型付け」があります。MJDには、静的型付けと動的型付けの見事な関係があります。
アモン

@amon同意しない。静的に型付けされた言語は、ボックス化されていない/値の型、dictsの代わりに構造体などを使用したため、一般に動的に型付けされた言語よりもかなり重要な利点があります。言語を選択する理由はそれだけではありません。私は可能な限りいつでも動的を使用しており、ほとんどの場合、パフォーマンスのペナルティは制限されているか、重要ではありません。そして、はい、ダイナミックを選択する他の動機があります。しかし、あなたはそこに行くために本当のことをあきらめます。
ジョナサンユーニス2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.