スクリプトプログラミング言語のサイトのメインページで好奇心をかきながら、次の文章に出会いました。
システムが大きくなりすぎて頭に残ることができない場合は、静的型を追加できます。
これは、静的なコンパイルされた言語(Javaなど)と動的な解釈された言語との間の多くの宗教戦争(主にPythonより使用されるためですが、ほとんどのスクリプト間で共有される「問題」)であることを思い出しました言語)、動的に型付けされた言語よりも静的に型付けされた言語のファンの不満の1つは、「いつの日か、関数の戻り値の型を忘れてしまい、静的に型付けされた言語では、すべてが明示的に宣言されていますが」.
私はこのような発言を理解していません。正直に言うと、関数の戻り値の型を宣言したとしても、コードの多くの行を記述した後はそれを忘れることができます。また、関数の検索機能を使用して宣言されている行に戻る必要があります。テキストエディタで確認してください。
さらに、関数はtype funcname()...
で宣言されているため、type
がわかっている場合はfuncname
しか知らないため、関数が呼び出される各行を検索する必要があります。 、Pythonなどでは、def funcname
またはfunction funcname
宣言時に一度だけ発生します。
さらに、REPLでは、関数の戻り値の型をさまざまな入力でテストするのは簡単ですが、静的に型付けされた言語では、コード行を追加して、宣言された型を知るためにすべてを再コンパイルする必要があります。
では、静的型付け言語の強みではない関数の戻り値の型を知る以外に、静的型付けは、より大きなプロジェクトでどのように役立つのでしょうか。
さらに、REPLを使用すると、さまざまな入力で関数の戻り値の型をテストするのは簡単です
それは簡単ではありません。ささいなことではありませんまったく。簡単な関数に対してこれを行うのは簡単です。
たとえば、戻り値の型が完全に入力の型に依存する関数を簡単に定義できます。
getAnswer(v) {
return v.answer
}
この場合、getAnswer
は実際にはhave単一の戻り値型ではありません。戻り値の型を知るためにサンプル入力を使用してこれを呼び出すテストを作成することはできません。 alwaysは実際の引数に依存します。実行時。
そして、これには、データベースの検索を実行するなどの機能さえ含まれていません。または、ユーザー入力に基づいて物事を行います。または、もちろん動的型であるグローバル変数を検索します。または、ランダムなケースで戻り値の型を変更します。言うまでもなく、すべての個々の機能を毎回手動でテストする必要があります。
getAnswer(x, y) {
if (x + y.answer == 13)
return 1;
return "1";
}
基本的に、一般的なケースで関数の戻り値の型を証明することは、文字通り数学的に不可能です(停止問題)。 onlyguaranteeへの戻り値の型は入力を制限して、証明できないプログラムを許可しないことにより、この質問への回答が停止問題の領域に入らないようにすることです。これが静的型付けが行うことです。
さらに、関数はfuncname()...タイプで宣言されているため、タイプがわかっている場合は、関数が呼び出される各行を検索する必要があります。これは、Pythonなどは、宣言時に一度だけ発生するdef funcnameまたはfunction funcnameを検索するだけです。
静的型付け言語には「ツール」と呼ばれるものがあります。これらは、ソースコードを使用して作業を行うのに役立つプログラムです。この場合、Resharperのおかげで、右クリックして定義に移動するだけです。または、キーボードショートカットを使用します。または、マウスを上に置くだけで、関係するタイプがわかります。私はgreppingファイルについて少しでも気にしません。テキストエディター自体は、プログラムのソースコードを編集するための哀れなツールです。
メモリから、def funcname
は、関数を任意に再割り当てできるため、Pythonでは十分ではありません。または、複数のモジュールで繰り返し宣言することもできます。またはクラスで。等。
テキストエディターの検索機能を使用して宣言されている行に戻って確認する必要があります。
関数名をファイルで検索することは、決して必要とされるべきではない恐ろしいプリミティブな操作です。これは、環境とツールの根本的な障害を表しています。 Python)でテキスト検索が必要になることさえ考えられるという事実は、Pythonに対する大きな問題です。
何年にもわたって変化した、多くのプログラマーがいるプロジェクトを考えてみてください。これを維持する必要があります。機能あり
getAnswer(v) {
return v.answer
}
それはいったい何をするのでしょうか? v
とは何ですか?要素answer
はどこから来たのですか?
getAnswer(v : AnswerBot) {
return v.answer
}
もう少し情報があります—; AnswerBot
のタイプが必要です。
クラスベースの言語に行けば、
class AnswerBot {
var answer : String
func getAnswer() -> String {
return answer
}
}
これで、タイプAnswerBot
の変数を取得してメソッドgetAnswer
を呼び出すことができ、誰もがその機能を知っています。ランタイムテストが行われる前に、変更はコンパイラによってキャッチされます。他の多くの例がありますが、おそらくこれはあなたにアイデアを与えますか?
判断を曇らせている可能性のある大規模な静的プロジェクトでの作業について、いくつかの誤解があるようです。ここにいくつかのポインタがあります:
関数の戻り値の型を宣言したとしても、コードの多くの行を記述した後は、それを忘れることができます。また、テキストエディターの検索関数を使用して宣言されている行に戻る必要があります。確認してください。
静的に型付けされた言語を扱うほとんどの人は、言語にIDEまたは言語固有のツールと統合されているインテリジェントエディター(vimやemacsなど)を使用します。通常、これらのツールで関数のタイプを見つける。たとえば、JavaプロジェクトのEclipseでは、通常、メソッドのタイプを見つける方法が2つあります。
someVariable.
)とEclipseはsomeVariable
のタイプを検索し、そのタイプで定義されているすべてのメソッドのドロップダウンリストを提供します。リストを下にスクロールすると、選択するとそれぞれのタイプとドキュメントが表示されます。エディターがsomeVariable
のタイプを判別するのが困難(または場合によっては不可能)であり、正しいリストを簡単に生成できないため、これを動的言語で実現することは非常に難しいことに注意してください。 this
でメソッドを使用したい場合は、ctrl + spaceを押すだけで同じリストを取得できます(ただし、この場合、動的言語ではそれほど難しくありません)。ご覧のとおり、これは動的言語で使用できる一般的なツールよりもいくらか優れています(動的言語では不可能とは言えないため、一部にはかなり優れたIDE機能があるため、 -Smalltalkはすぐに頭に浮かぶものです-しかし、動的言語にとっては難しいため、利用できる可能性は低くなります)。
さらに、関数はfuncname()...タイプで宣言されているため、タイプがわかっている場合は、関数が呼び出される各行を検索する必要があります。これは、Pythonなどは、宣言時に一度だけ発生するdef funcnameまたはfunction funcnameを検索するだけです。
静的言語ツールは通常、セマンティック検索機能を提供します。つまり、テキスト検索を実行する必要なく、特定のシンボルの定義と参照を正確に見つけることができます。たとえば、JavaプロジェクトにEclipseを使用すると、テキストエディターでシンボルを強調表示して右クリックし、「定義に移動」または「参照を検索」を選択して、これらのいずれかを実行できます。あなたのエディタはそれがどこにあるか正確に知っているので、関数定義のテキストを検索する必要はありません。
ただし、逆に、テキストでメソッド定義を検索することは、大規模な動的プロジェクトでは実際には機能しません。そのようなプロジェクトには同じ名前のメソッドが複数存在する可能性があり、どのツールを呼び出すかを明確にするためにすぐに利用できるツール(そのようなツールは最高の状態で書くのが難しい、または一般的なケースでは不可能であるため)なので、手動で行う必要があります。
さらに、REPLを使用すると、さまざまな入力で関数の戻り値の型をテストするのは簡単です
REPLを使用することは不可能ではありません。Haskellは思い浮かぶ例ですが、他の静的型付け言語のREPLもあります。しかし、要点は静的言語で関数の戻り値の型を見つけるためにコードを実行する必要はありません-これは、何も実行せずに調査によって決定できます。
静的に型付けされた言語では、宣言された型を知るためだけに、コード行を追加してすべてを再コンパイルする必要があります。
これを行う必要がある場合でも、すべてを再コンパイルする必要はないでしょう。最近のほとんどの静的言語には、変更されたコードのごく一部のみをコンパイルするインクリメンタルコンパイラーがあり、型エラーを作成した場合、ほぼ瞬時にフィードバックを得ることができます。たとえば、Eclipse/Javaはタイプエラーを強調表示しますまだタイプしている間。
たとえば、javascript、RubyまたはSmalltalk)と比較すると、開発者は実行時にコア言語機能を再定義するため、大きなプロジェクトの理解が難しくなります。
より大きなプロジェクトには、より多くの人がいるだけでなく、より多くの時間があります。誰もが忘れたり、先に進むのに十分な時間。
事例として、私の知人はLISPで安全な「Job For Life」プログラミングを行っています。チーム以外は誰もコードベースを理解できません。
古いことわざ「ガベージイン、ガベージアウト」を覚えていますか。まあ、これは静的型付けが防ぐのに役立つものです。万能の万能薬ではありませんが、ルーチンがどのような種類のデータを受け入れて返すかについての厳密さは、正しく処理していることを保証することを意味します。
そのため、整数を返すgetAnswerルーチンは、文字列ベースの呼び出しで使用しようとすると役に立ちません。静的型付けは、おそらく間違いを犯していることに気をつけるようにすでに指示しています。 (そして、確かに、それをオーバーライドできますが、それがあなたがやっていることを正確に知る必要があり、キャストを使用してコードでそれを指定します。しかし、一般的には、これをしたくない-ハッキング四角い穴への丸い止め釘は結局うまくいきません)
これで、複雑な型を使用して、鉱石の機能を持つクラスを作成することで、さらに処理を進めることができます。これらを渡し始めると、プログラムの構造が突然大きくなります。構造化プログラムは、正しく機能させ、維持するのがはるかに簡単なプログラムです。