ダックタイピングと比較した場合の利点は何ですか?静的型付け?

StackOverflow https://stackoverflow.com/questions/47972

  •  09-06-2019
  •  | 
  •  

質問

私は Groovy についてさらに調査と実験を行っており、Java では実行できないことや実行できないことを Groovy で実装することのメリットとデメリットについて考えをまとめようとしています。私は静的言語と強く型付けされた言語にどっぷり浸かっていたので、私にとって動的プログラミングはまだ単なる概念にすぎません。

Groovy は私に次のような能力を与えてくれます。 アヒル型, しかし、その価値があまりわかりません。ダックタイピングは静的タイピングよりどのように生産性が高いのでしょうか?コードの利点を理解するには、コードの練習でどのようなことを行うことができますか?

Groovy を念頭に置いてこの質問をしていますが、必ずしも Groovy の質問ではないことは理解しているので、すべてのコード キャンプからの回答を歓迎します。

役に立ちましたか?

解決

次に、どちらが良いかというと、EMACS か vi?これは進行中の宗教戦争の一つです。

次のように考えてください。あらゆるプログラム 正しい, 、言語が静的に型指定されている場合は正しくなります。静的型付けの機能は、実行時ではなくコンパイル時に型の不一致を検出するのに十分な情報をコンパイラーに提供することです。これは、インクリメンタルな種類のプログラミングを行っている場合には迷惑になる可能性がありますが、プログラムについて明確に考えている場合には、それほど問題ではありません (私は主張します)。一方で、オペレーティング システムや電話交換機など、数十人、数百人、数千人が作業する非常に大きなプログラム、または非常に高い信頼性要件を必要とするプログラムを構築している場合、コンパイラは次のことを行うことができます。適切なコード パスを実行するためのテスト ケースを必要とせずに、大規模なクラスの問題を検出できます。

動的型付けが新しくて別のものであるかというと、そうではありません。たとえば、C は常に をキャストできるため、事実上動的に型指定されます。 foo*bar*. 。それは、C プログラマーとして、適切なコードを決して使用しないことが私の責任であることを意味します。 bar* アドレスが実際に foo*. 。しかし、大規模なプログラムの問題の結果、C は lint(1) のようなツールを成長させ、その型システムを強化しました。 typedef そして最終的には、C++ で厳密に型指定されたバリアントを開発しました。(そしてもちろん、C++ は、あらゆる種類のキャスト、ジェネリックス/テンプレート、および RTTI を使用して、強力な型付けを回避する方法を開発しました。

ただし、もう 1 つ注意してください。「アジャイル プログラミング」と「動的言語」を混同しないでください。 アジャイルプログラミング これは、人々がプロジェクトで協力する方法についてです。プロジェクトは、プログラマーにとって人道的な環境を維持しながら、顧客のニーズを満たすために変化する要件に適応できるでしょうか?それは動的型付け言語で行うことができ、より生産性が高いためそうであることがよくありますが (Ruby、Smalltalk など)、C やアセンブラでも実行でき、成功しています。実際には、 ラリー展開 アジャイル手法 (特に SCRUM) を使用してマーケティングや文書化を行うこともあります。

他のヒント

ダックタイピングに対するコメントの多くは、その主張を裏付けるものではありません。型について「心配する必要がない」ということは、メンテナンスやアプリケーションを拡張可能にするために持続可能ではありません。私は前回の契約で Grails の動作を見る良い機会に恵まれましたが、実際に見るのは非常に面白いものでした。誰もが「アプリを作成」して実行できるようになったことに満足していますが、残念なことに、バックエンドですべてが追いついてしまいます。

Groovyも私には同じように思えます。確かに、非常に簡潔なコードを書くことができますし、プロパティやコレクションなどを扱う方法には確かに優れた機能がいくつかあります...しかし、一体何がやり取りされているのか分からないことによる代償は、ますます悪化するばかりです。ある時点で、なぜプロジェクトの 80% がテストで 20% が作業になってしまったのか、頭を悩ませたことがあるでしょう。ここでの教訓は、コードが「小さく」なれば「読みやすく」なるわけではないということです。申し訳ありませんが、そのロジックは単純です。直観的に知らなければならないことが増えれば増えるほど、コードを理解するプロセスはより複雑になります。それが、GUI が長年にわたって過度に象徴的になるのを控えてきた理由です。確かに見た目はきれいですが、何が起こっているのかは必ずしも明白ではありません。

そのプロジェクトの人々は、学んだ教訓を「確実に理解する」のに苦労していたようですが、型 T の単一要素、T の配列、ErrorResult、または null のいずれかを返すメソッドがある場合...それはかなり明らかになります。

ただし、Groovy を使用することで私にとって効果があったことが 1 つあります。それは、請求にかかる時間がすごいということです。

驚くべき静的型システムを備えた Haskell を使用している場合、静的型付けに問題はありません。ただし、Java や C++ など、非常に不安定な型システムを備えた言語を使用している場合、ダック タイピングは間違いなく改善になります。

次のような単純なものを使用しようとしていると想像してみてください。地図" Java では (いや、そういう意味ではありません) データ構造)。ジェネリック医薬品でさえサポートがかなり不十分です。

アヒル タイピングは、入力時にエラーを指摘する可能性がある最新の IDE の静的チェックを無効にします。これを利点と考える人もいます。IDE/コンパイラに、私が愚かなプログラマのトリックを行ったことをできるだけ早く教えてもらいたいのです。

私の最近のお気に入りの議論 に対して ダックタイピングは Grails プロジェクト DTO から来ています。

class SimpleResults {
    def results
    def total
    def categories
}

どこ results のようなものになります Map<String, List<ComplexType>>, これは、作成場所が見つかるまで、さまざまなクラスのメソッド呼び出しの痕跡をたどることによってのみ発見できます。末期的な好奇心旺盛な人にとっては、 total のサイズの合計です。 List<ComplexType>categories のサイズです Map

元の開発者には明らかだったかもしれませんが、メンテナンスが下手な私 (ME) は、これを追跡して大量の髪の毛を失いました。

ダックタイピングを少し使ってみないと、その価値を理解するのは少し難しいです。一度慣れてしまえば、インターフェイスを扱わなくて済むことや、正確にどのような型なのかを気にする必要がないことが、どれだけ心の負担を軽くするかが分かるでしょう。

私見ですが、変数やメソッドに一貫した名前を付けるなど、いくつかの規則に従うと、ダック タイピングの利点がさらに大きくなります。から例を挙げると、 ケン・G, 、次のように読むのが最適だと思います。

class SimpleResults {
    def mapOfListResults
    def total
    def categories
}

「calculateRating(A,B)」という名前の操作でコントラクトを定義し、A と B が別のコントラクトに従うとします。擬似コードでは次のようになります。

Long calculateRating(A someObj, B, otherObj) {

   //some fake algorithm here:
   if(someObj.doStuff('foo') > otherObj.doStuff('bar')) return someObj.calcRating());
   else return otherObj.calcRating();

}

これを Java で実装したい場合は、A と B の両方が次のような何らかのインターフェイスを実装する必要があります。

public interface MyService {
    public int doStuff(String input);
}

さらに、評価を計算するための契約を一般化したい場合 (評価計算用に別のアルゴリズムがあるとします)、インターフェイスも作成する必要があります。

public long calculateRating(MyService A, MyServiceB);

ダックタイピングを使用すると、 インターフェース そして、実行時にAとBの両方が正しく応答することを信頼してください。 doStuff() 呼び出します。特定の契約定義は必要ありません。これはあなたにとって有利に働くこともありますが、不利に働くこともあります。

欠点は、他の人がコードを変更したときにコードが壊れないことを保証するために、細心の注意を払う必要があることです (つまり、他の人はメソッド名と引数に関する暗黙の契約を認識している必要があります)。

これは、特に Java では構文がそれほど簡潔ではないため、さらに悪化することに注意してください (Java と比べて)。 スカラ座 例えば)。これの反例は次のとおりです リフトフレームワーク, 、フレームワークの SLOC カウントは次のようなものであると言われています。 レール, ただし、テスト内で型チェックを実装する必要がないため、テスト コードの行数は少なくなります。

ここでは、ダック タイピングによって作業が軽減される 1 つのシナリオを示します。

これは非常に簡単なクラスです

class BookFinder {
    def searchEngine

    def findBookByTitle(String title) {
         return searchEngine.find( [ "Title" : title ] ) 
    }
}

次に単体テストです。

void bookFinderTest() {
    // with Expando we can 'fake' any object at runtime.
    // alternatively you could write a MockSearchEngine class.
    def mockSearchEngine = new Expando()
    mockSearchEngine.find = {
        return new Book("Heart of Darkness","Joseph Conrad")
    }

    def bf = new BookFinder()
    bf.searchEngine = mockSearchEngine
    def book = bf.findBookByTitle("Heart of Darkness")
    assert(book.author == "Joseph Conrad"
}

静的型チェックがないため、SearchEngine を Expando に置き換えることができました。静的型チェックでは、SearchEngine がインターフェイス、または少なくとも抽象クラスであることを確認し、その完全なモック実装を作成する必要がありました。これには労力がかかりますが、洗練された単一目的のモック フレームワークを使用することもできます。しかし、ダックタイピングは汎用性があり、私たちを助けてくれました。

ダックタイピングのため、単体テストでは、呼び出されるメソッドを実装している限り、依存関係の代わりに古いオブジェクトを提供できます。

強調しておきますが、インターフェイスとクラス階層を注意深く使用すれば、静的に型付けされた言語でこれを行うことができます。しかし、ダックタイピングを使用すると、あまり考えず、少ないキーストロークでタイピングを行うことができます。

それがダックタイピングの利点です。動的型付けがあらゆる状況で使用するのに適したパラダイムであるという意味ではありません。私の Groovy プロジェクトでは、型に関するコンパイラの警告が役立つと思われる状況では、Java に戻ることを好みます。

と、 TDD + 100% コードカバレッジ + IDE ツールを使用して常にテストを実行できるため、静的型付けの必要性を感じなくなりました。強力な型がないため、単体テストが非常に簡単になりました (モック オブジェクトの作成に Map を使用するだけです)。特に、ジェネリックを使用している場合、違いがわかります。

//Static typing 
Map<String,List<Class1<Class2>>> someMap = [:] as HashMap<String,List<Class1<Class2>>>

//Dynamic typing
def someMap = [:]   

ダックタイピングが静的タイピングよりも生産性が高いというわけではなく、単に静的タイピングが異なるだけです。静的型付けでは、データが正しい型であるかどうかを常に心配する必要がありますが、Java では、正しい型にキャストすることでデータが表示されます。ダックタイピングでは、メソッドが適切である限り型は重要ではないため、実際には型間のキャストや変換の多くの手間が省けます。

@クリス・バンチ

静的型付けがダックタイピングよりも生産性が高いというわけではなく、単に異なるだけです。ダック タイピングでは、データに正しいメソッドがあるかどうかを常に心配する必要があります。JavaScript や Ruby では、多くのメソッド テストを通じてそれが判明します。静的型付けでは、それが正しいインターフェイスである限り問題はないため、型間のテストや変換の多くの手間が省けます。

申し訳ありませんが、そうする必要がありました...

私の意見:

動的型付けまたはアヒル型付けされた言語はおもちゃです。Intellisense を利用できないため、コンパイル時間 (または編集時間 - VS のような本物の IDE (他の人が IDE だと思っているようなゴミではない) を使用している場合) のコード検証が失われます。

静的に型付けされていない言語は避けてください。それ以外の言語はすべて単なる自虐的です。

私にとって、動的型付け言語を、すべてが十分に抽象的な基本クラスから継承する単なる静的型付けの形式として見るのであれば、それらはそれほど違いはありません。

多くの人が指摘しているように、これが奇妙になり始めたときに問題が発生します。誰かが、単一のオブジェクト、コレクション、または null を返す関数を指摘しました。関数が複数の型ではなく特定の型を返すようにします。単一の関数とコレクションの場合は複数の関数を使用します。

要するに、誰でも悪いコードを書くことができるということです。静的タイピングは優れた安全装置ですが、髪に風を感じたいときにヘルメットが邪魔になることがあります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top