動的言語に本当の利点はありますか?[閉まっている]


29

まず、Javaが私がこれまでに使用した唯一の言語であると言いたいので、この主題に関する私の無知を許してください。

動的に型付けされた言語を使用すると、任意の変数に任意の値を入力できます。したがって、たとえば次の関数(psuedocode)を作成できます。

void makeItBark(dog){
    dog.bark();
}

そして、どんな値でも内部に渡すことができます。値にbark()メソッドがある限り、コードが実行されます。それ以外の場合は、ランタイム例外または同様の例外がスローされます。(これについて間違っている場合は修正してください)。

一見、これはあなたに柔軟性を与えます。

しかし、私は動的言語でいくつかの読書をしました。人々が言うことは、動的言語でコードを設計または記述するとき、静的に型付けされた言語と同じように、型について考えて考慮することです。

そのため、たとえばmakeItBark()関数を記述するとき、「 'えるもの」のみを受け入れるように意図しますが、これらの種類のものだけを渡すようにする必要があります。唯一の違いは、間違いを犯したときにコンパイラが通知しないことです。

確かに、このアプローチには1つの利点があります。つまり、静的言語では、「この関数はbarえるものをすべて受け入れる」ことを実現するには、明示的なBarkerインターフェイスを実装する必要があります。それでも、これは小さな利点のようです。

何か不足していますか?動的に型付けされた言語を使用することで実際に得られるものは何ですか?


6
makeItBark(collections.namedtuple("Dog", "bark")(lambda x: "woof woof"))。その引数はクラスではなく、匿名の名前付きタプルです。ダックタイピング(「if it quacks a ...」)を使用すると、基本的に制限がなく、構文オーバーヘッドのないアドホックインターフェイスを実行できます。Javaのような言語でこれを行うことはできますが、多くの乱雑なリフレクションが発生します。Javaの関数にArrayListが必要で、別のコレクションタイプを指定する場合は、SOLです。Pythonでも、それは実現できません。
Phoshi

2
この種の質問は以前に尋ねられました:hereherehere。具体的には、最初の例が質問に答えているようです。たぶん、あなたはそれを明確にするためにあなたのものを言い換えることができますか?
logc 14

3
たとえば、C ++では、メソッドを持つ任意のタイプTで動作するテンプレート関数を使用できます。bark()コンパイラは、何か間違ったことを渡すと文句を言いますが、実際にはbark()を含むインターフェイスを宣言する必要はありません。
ウィルバート14

2
@Phoshi Pythonの引数は、特定の型である必要があります。たとえば、数値を指定することはできません。独自のオブジェクトのアドホック実装があり、カスタムgetMember関数を介してそのメンバーを取得するmakeItBark場合、のdog.bark代わりにを呼び出したために爆発しますdog.getMember("bark")。コードを機能させるのは、Pythonのネイティブオブジェクトタイプを使用することに全員が暗黙的に同意することです。
ドーバル14

2
@Phoshi Just because I wrote makeItBark with my own types in mind doesn't mean you can't use yours, wheras in a static language it probably /does/ mean that.私の答えで指摘したように、これは一般的なケースはありません。これはJavaとC#の場合ですが、これらの言語は型とモジュールシステムに障害があり、静的型付けができることの代表ではありません。私は完全にジェネリックを書くことができmakeItBark、いくつかの静的型付け言語、C ++またはDのようにも非機能的なものに
Doval

回答:


35

動的に型付けされた言語はユニタイプです

型システムを比較すると、動的型付けには利点がありません。動的型付けは、静的型付けの特殊なケースです。これは、すべての変数が同じ型を持つ静的型付け言語です。すべての変数をtype Objectにし、「オブジェクト」値をtypeにすることで、Javaで同じこと(簡潔さを除く)を実現できますMap<String, Object>

void makeItBark(Object dog) {
    Map<String, Object> dogMap = (Map<String, Object>) dog;
    Runnable bark = (Runnable) dogMap.get("bark");
    bark.run();
}

そのため、リフレクションがなくても、静的に型付けされたほぼすべての言語で同じ効果を達成できますが、構文上の利便性は別です。追加の表現力は得られません。逆に、あなたが持っているより少ない動的型付け言語では、あなたがしているので、表現力を拒否された特定の種類の変数を制限する機能を。

静的に型付けされた言語でアヒルの樹皮を作る

さらに、静的に型指定された適切な言語を使用すると、bark操作を持つ任意の型で機能するコードを作成できます。Haskellでは、これは型クラスです:

class Barkable a where
    bark :: a -> unit

これは、あるタイプaがBarkableと見なさbarkれるには、そのタイプの値を取り、何も返さない関数が存在する必要があるという制約を表します。

その後、Barkable制約の観点から汎用関数を作成できます。

makeItBark :: Barkable a => a -> unit
makeItBark barker = bark (barker)

これは、makeItBarkBarkable要件を満たしているすべてのタイプで機能するということです。これは次のように見えるかもしれませんがinterface、JavaやC#で、それは一つの大きな利点を持っている-のタイプを指定する必要はありません前まで、彼らは満足型クラスを。私が書いていないサードパーティのタイプであっても、そのタイプDuckBarkableいつでも言うことDuckができます。実際、ライターが関数をDuck記述していなくてもかまいません。次の条件を満たすbark言語を伝えると、事後に提供できます。DuckBarkable

instance Barkable Duck where
    bark d = quack (punch (d))

makeItBark (aDuck)

これは、Ducksがbarえることができ、barえる前にカモをdでることによってそのbarえ声機能が実装されていることを示しています。邪魔にならないように、makeItBarkアヒルを呼ぶことができます。

Standard MLさらにOCaml同じ型クラスを複数の方法で満たすことができるという点で、さらに柔軟です。これらの言語では、整数は従来の順序を使用して順序付けすることができ、次に向きを変えて、割り切れる順序で並べることできます(10 > 510は5で割り切れるなど)。Haskellでは、型クラスを1回だけインスタンス化できます。(これにより、Haskell barkはアヒルを呼び出しても問題ないことを自動的に認識できます。SMLまたはOCaml では、複数の関数があるため、どの bark関数を使用するかを明示する必要があります。)

簡潔

もちろん、構文上の違いがあります。あなたが提示したPythonコードは、私が書いたJavaの同等物よりもはるかに簡潔です。実際には、その簡潔さが動的に型付けされた言語の魅力の大きな部分です。ただし、型推論を使用すると、すべての変数の型を明示的に記述する必要がなくなるため、静的に型付けされた言語と同じくらい簡潔なコードを記述できます。静的に型付けされた言語は、動的な型付けのネイティブサポートも提供し、すべてのキャストとマップ操作(C#などdynamic)の冗長性を取り除きます。

正しくても型が正しくないプログラム

公平を期すために、静的型付けは、型チェッカーで検証できない場合でも、技術的に正しいプログラムを除外する必要があります。例えば:

if this_variable_is_always_true:
    return "some string"
else:
    return 6

ifelse分岐は発生しませんが、ほとんどの静的型付け言語はこのステートメントを拒否します。実際には、誰もこのタイプのコードを利用していないようです。タイプチェッカーにとって賢いものは、おそらくあなたのコードの将来のメンテナーがあなたとあなたの次の親族を呪うでしょう。適切な例として、誰かが4つのオープンソースPythonプロジェクトをHaskellに正常に翻訳しました。つまり、優れた静的型付け言語ではコンパイルできないものは何もしていませんでした。さらに、コンパイラーは、ユニットテストでは検出できないタイプ関連のバグをいくつか発見しました。

動的型付けについて私が見た中で最も強い議論は、言語の構文を任意に拡張できるLispのマクロです。しかし、Typed Racketは静的に型付けされたLispの方言であり、マクロを持っているため、静的な型付けとマクロは相互に排他的ではないようですが、同時に実装するのはおそらく困難です。

リンゴとオレンジ

最後に、言語には単なる型システムよりも大きな違いがあることを忘れないでください。Java 8より前は、Javaであらゆる種類の関数型プログラミングを行うことは事実上不可能でした。単純なラムダには、4行の定型的な匿名クラスコードが必要です。Javaは、コレクションリテラル(例:)もサポートしていません[1, 2, 3]。また、ツール(IDE、デバッガー)、ライブラリ、およびコミュニティサポートの品質と可用性にも違いがある場合があります。誰かがJavaよりもPythonやRubyで生産性が高いと主張したとき、その機能の不均衡を考慮する必要があります。含まれているすべてのバッテリー言語コア、および型システムを使用した言語の比較には違いがあります


2
-あなたが最初の段落のためのあなたの源属性を忘れてしまったexistentialtype.wordpress.com/2011/03/19/...

2
@Matt Re:1、重要ではないと思い込んではいません。私は簡潔さの下でそれに対処しました。日時:2、私は明示的に言ったことはありませんが、「良い」とは「徹底的な型推論」を意味し、「事実の後にコードを型シグネチャに一致させるモジュールシステム」を意味し、Java / C#のインターフェイス。Re 3、証明の負担は、同等の構文と機能を備えた2つの言語、1つは動的に型付けされ、もう1つは完全な型推論を備えている場合、両方で等しい長さのコードを書くことができないことを説明することです。
ドーバル

3
@MattFenwick私はすでに正当化しています-同じ機能を備えた2つの言語、動的に型付けされた言語と静的に型付けされた言語を考えると、それらの間の主な違いは型注釈の存在であり、型推論はそれを取り去ります。構文のその他の違いは表面的なものであり、機能の違いは比較をリンゴとオレンジに変えます。この論理がいかに間違っているかを示すのはあなた次第です。
ドーバル14

1
Booをご覧ください。型推論で静的に型付けされ、言語の構文を拡張できるマクロがあります。
メイソンウィーラー

1
@Doval:True。ところで、ラムダ表記は関数型プログラミングでのみ使用されるわけではありません。私の知る限り、Smalltalkは匿名ブロックを持ち、Smalltalkはできるだけオブジェクト指向です。そのため、多くの場合、これが匿名関数であるか、匿名メソッドを1つだけ持つ匿名オブジェクトであるかに関係なく、いくつかのパラメーターを持つ匿名コードブロックを渡すことが解決策です。これらの2つの構造は、2つの異なる視点(機能的視点とオブジェクト指向視点)から本質的に同じアイデアを表現していると思います。
ジョルジオ14

11

これは難しく、非常に主観的な問題です。(そしてあなたの質問は意見に基づいて閉じられるかもしれませんが、それは悪い質問であることを意味しません-反対に、そのようなメタ言語の質問について考えることは良い兆候です-それはQ&A形式にはあまり適していませんこのフォーラムの。)

私の見解は次のとおりです。高水準言語のポイントは、プログラマーがコンピューターでできることを制限することです。彼らは目的がユーザーに与えることであると考えているので、これは、多くの人々に驚くべきことであるより多くの電力をして達成より。しかし、Prolog、C ++、またはListで記述したものはすべて最終的にマシンコードとして実行されるため、実際には、アセンブリ言語がすでに提供している以上の能力をプログラマに与えることは不可能です。

高レベル言語のポイントは、プログラマーが自分で作成したコードをよりよく理解し、同じことをより効率的に行えるようにすることです。サブルーチン名は、16進アドレスより覚えやすいです。自動引数カウンターは、ここでの呼び出しシーケンスよりも使いやすく、何の助けもなしに、自分で正確に引数の数を取得する必要があります。型システムはさらに進んで、特定の場所で提供できる引数の種類を制限します。

ここで人々の認識が異なります。一部の人々(私もその中にいます)は、パスワードチェックルーチンがとにかく正確に2つの引数、および常に文字列とそれに続く数値IDを期待している限り、コードでこれを宣言し、後でそのルールに従うことを忘れます。このような小規模なブックキーピングをコンパイラーにアウトソーシングすることで、より高いレベルの懸念から解放され、システムの設計と設計が向上します。したがって、型システムは正味の勝利です。つまり、型システムはコンピューターに得意なことをさせ、人間は得意なことをさせます。

他の人はまったく違った見方をしています。彼らは何をすべきかコンパイラーに言われることを嫌います。彼らは、型宣言を決定してそれを入力するための余分な先行投資を嫌います。彼らは、どのタイプと引数をどこで使用するかを正確に伝える計画を立てに、実際のビジネスコードを記述する探索的プログラミングスタイルを好みます。そして、彼らが使用するプログラミングのスタイルについては、それは非常に真実かもしれません。

もちろん、ここでは恐ろしく単純化しすぎています。型チェックは、明示的な型宣言に厳密には結び付けられていません。型推論もあります。実際にさまざまなタイプの引数を取るルーチンを使用したプログラミングでは、そうでなければ不可能である非常に異なる非常に強力なことが可能になります。

最終的に、そのような異なる言語が非常に人気があり、絶滅の兆候を示さないという事実は、人々がプログラミングを非常に異なって行っていることを示しています。プログラミング言語の機能は、主に人間の要因(人間の意思決定プロセスをより良くサポートするもの)に関係していると思います。


3
答えてくれてありがとう。あなたは、コンパイラによって何をすべきかを言われるのを嫌うもいると言いました。[..]彼らは、どのタイプと引数をどこで使用するかを正確に伝える計画を立てずに、実際のビジネスコードを記述する探索的プログラミングスタイルを好みます。これは私が理解できないことです。プログラミングは音楽の即興演奏とは違います。音楽では、間違った音を打つと、クールに聞こえるかもしれません。プログラミングでは、存在するはずのない関数に何かを渡すと、ほとんどの場合、厄介なバグが発生します。(次のコメントに続く)。
アビブコーン14

3
私は同意しますが、多くの人同意しません。そして、特に彼らはしばしば彼らを知らないので、人々は彼らの精神的な先入観について非常に所有しています。だからこそ、プログラミングスタイルについての議論は通常、議論や戦いに退屈し、インターネット上でランダムな見知らぬ人から始めるのはめったに役に立ちません。
キリアンフォス14

1
これが、私が読んだことから判断すると、動的言語を使用している人が静的言語を使用している人と同じように型を考慮する理由です。あなたが関数を書くとき、それは特定の種類の引数を取るべきだからです。コンパイラがこれを強制するかどうかは関係ありません。そのため、これは静的型付けに役立ちますが、動的型付けはそうではありません。どちらの場合も、関数は特定の種類の入力を取得する必要があります。したがって、動的型付けの利点はわかりません。「探索的プログラミングスタイル」を好む場合でも、必要なものを関数に渡すことはできません。
アビブコーン14

1
人々はしばしば非常に異なるタイプのプロジェクトについて話します(特にサイズに関して)。Webサイトのビジネスロジックは、完全なERPシステムと比較すると非常に単純です。物事を間違えるリスクは少なく、いくつかのコードを非常に簡単に再利用できるという利点はより重要です。データ構造からPDF(またはHTML)を生成するコードがあるとします。今、私は異なるデータソースを持っています(最初はいくつかのREST APIからのJSONでしたが、現在はExcelインポーターです)。Rubyのような言語では、最初の構造を「シミュレート」し、「樹皮を作り」、Pdfコードを再利用するのは非常に簡単です。
トールステンミュラー14

@Prog:動的言語の本当の利点は、静的型システムでは非常に難しいことを記述することになります。たとえば、Pythonの関数は、関数参照、ラムダ、関数オブジェクト、または神が何を知っているかであり、すべて同じように機能します。別のオブジェクトをラップし、構文のオーバーヘッドがゼロのメソッドを自動的にディスパッチするオブジェクトを構築できます。また、すべての関数は基本的にパラメータ化された型を持ちます。動的言語は、迅速に作業を完了するために素晴らしいです。
Phoshi

5

動的言語を使用して記述されたコードは、静的型システムに結合されていません。したがって、このようなカップリングの欠如は、貧弱/不十分な静的型システムと比較して利点です(ただし、大きな静的型システムと比較すると、洗浄または不利な場合があります)。

さらに、動的言語の場合、静的型システムを設計、実装、テスト、および保守する必要はありません。これにより、静的型システムを備えた言語に比べて実装が簡単になります。


2
人々は最終的にユニットテストで基本的な静的型システムを再実装する傾向にありませんか?
デン14

また、ここで「結合」とはどういう意味ですか?たとえばマイクロサービスアーキテクチャでどのように現れますか?
デン14

@Den 1)良い質問ですが、OPと私の答えの範囲外であると感じています。2)この意味でのカップリングを意味します。手短に言えば、異なる型システムは、その言語で書かれたコードに異なる(互換性のない)制約を課します。申し訳ありませんが、最後の質問に答えることはできません。この点でマイクロサービスの特別な点がわかりません。

2
@Den:非常に良い点:私は、Pythonで書いた単体テストが、静的に型付けされた言語のコンパイラーによってキャッチされるエラーをカバーすることをよく観察します。
ジョルジオ14

@MattFenwick:あなたは、「...動的言語の場合、静的型システムを設計、実装、テスト、および保守する必要がない」という利点があると書きました。そしてDenは、コード内で直接型を設計およびテストする必要がある場合が多いことを観察しました。そのため、労力は取り除かれず、言語設計からアプリケーションコードに移行しました。
ジョルジオ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.