web-dev-qa-db-ja.com

動的言語に本当の利点はありますか?

まず、Javaは今まで使用した唯一の言語です。ですので、この件についての無知を許してください。

動的に型付けされた言語を使用すると、任意の変数に任意の値を入れることができます。したがって、たとえば次の関数(疑似コード)を記述できます。

_void makeItBark(dog){
    dog.bark();
}
_

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

どうやら、これはあなたに柔軟性を与えます。

しかし、私は動的言語についていくらか読みましたが、人々が言うことは動的言語でコードを設計または作成するときは、静的型付けの場合と同様に、型について考え、それらを考慮に入れます言語

したがって、たとえばmakeItBark()関数を記述する場合、「吠える可能性のあるもの」のみを受け入れることを意図し、これらの種類のものだけを渡すことを確認する必要があります。唯一の違いは、コンパイラーは、いつミスをしたかを知らせないことです。

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

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

29
Aviv Cohn

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

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

_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の要件を満たすすべての型で機能することを示しています。これはJavaまたはC#のinterfaceに似ているように見えるかもしれませんが、1つの大きな利点があります。型は、 up front がどの型クラスを満たすかを指定する必要はありません。 Duckは、私が記述しなかったサードパーティの型であっても、いつでもBarkableDuckであると言えます。実際、Duckの作成者がbark関数を記述していなくても問題ありません。DuckBarkableを満たすことを言語に伝えれば、事後的に提供できます。

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

makeItBark (aDuck)
_

これは、Ducksが吠える可能性があることを示しており、その鳴き声機能は、 アヒルをパンチする によって実装されてから、いんちきする前に実行されます。これで、アヒルのmakeItBarkを呼び出すことができます。

_Standard ML_およびOCamlは、 same 型クラスを複数の方法で満たすことができるという点で、さらに柔軟性があります。これらの言語では、整数は従来の順序を使用して順序付けでき、それから向きを変えて、 also 可分性で順序付けできると言います(例:_10 > 5_ 10は割り切れるため) 5)。 Haskellでは、型クラスをインスタンス化できるのは1回だけです。 (これにより、Haskellはアヒルでbarkを呼び出しても問題ないことを自動的に認識できます。SMLまたはOCamlでは、 which bark関数を明示的に指定する必要があります。 1。)

簡潔

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

正しいが型が間違っているプログラム

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

_if this_variable_is_always_true:
    return "some string"
else:
    return 6
_

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

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

リンゴとオレンジ

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

35
Doval

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

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

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

ここで人々の認識が異なります。一部の人々(私もその1つです)は、パスワードチェックルーチンが2つの引数を常に期待し、常に文字列の後に数値IDが続くことを期待している限り、これをコードで宣言し、次の場合に自動的に通知されると便利だと考えています後でそのルールに従うことを忘れます。このような小規模な簿記をコンパイラーにアウトソーシングすることで、より高いレベルの懸念から解放され、システムの設計と構築をより良くすることができます。したがって、タイプシステムは正味の勝利です。つまり、タイプシステムは、コンピューターが得意なことをできるようにし、人間が得意なことをできるようにします。

他の人はまったく違う見方をしています。彼らはコンパイラーが何をすべきか言われるのを嫌います。彼らは、型宣言を決定してそれを型付けするための余分な事前の努力を嫌います。彼らは、実際のビジネスコードを書く探索的なプログラミングスタイルを好んでいますなしどこでどのタイプと引数を使用するかを正確に伝える計画を持っています。そして、彼らが使用するプログラミングのスタイルについては、それはかなり本当かもしれません。

もちろん、私はひどく単純化しすぎています。型チェックは明示的な型宣言に厳密に結び付けられているわけではありません。型推論もあります。さまざまな型の引数を実際にとるルーチンを使用したプログラミングは、そうでなければ不可能である非常に異なる非常に強力なことを可能にします。多くの人々は、そのような余裕をうまく使用するのに十分な注意力と一貫性がないというだけです。

結局のところ、そのような異なる言語は非常に人気があり、消滅の兆候が見られないという事実は、人々がプログラミングを非常に異なって行っていることを示しています。プログラミング言語の機能は主にヒューマンファクター(人間の意思決定プロセスをより良くサポートするもの)に関するものであり、人々がまったく異なる方法で作業する限り、市場は非常に異なるソリューションを同時に提供します。

11
Kilian Foth

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

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

5
user39685