開発者が動的に型付けされた言語で型を指定できないのはなぜですか?


14

私が知っている動的に型付けされた言語は、開発者に変数の型を指定させたり、少なくともそれを非常に限定的にサポートさせたりすることはありません。

たとえば、JavaScriptは、便利な場合に変数のタイプを強制するメカニズムを提供しません。PHPを使用すると、メソッドの引数のいくつかのタイプを指定できますが、ネイティブ型(使用する方法はありませんintstring引数のために、など)、および引数以外の型を強制する方法はありません。

同時に、手動で型チェックを行うのではなく、場合によっては動的に型付けされた言語で変数の型を指定する選択肢があると便利です。

なぜそのような制限があるのですか?技術的/パフォーマンス上の理由(JavaScriptの場合)なのか、政治的な理由(PHPの場合)なのか?これは、私がよく知らない動的に型付けされた他の言語の場合ですか?


編集:回答とコメントに続いて、説明の例を示します。プレーンなPHPに次のメソッドがあるとします。

public function CreateProduct($name, $description, $price, $quantity)
{
    // Check the arguments.
    if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
    if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
    if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
    if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

多少の努力をすれば、これを次のように書き換えることができます(PHPのコントラクトによるプログラミングも参照)。

public function CreateProduct($name, $description, $price, $quantity)
{
    Component::CheckArguments(__FILE__, __LINE__, array(
        'name' => array('value' => $name, 'type' => VTYPE_STRING),
        'description' => array('value' => $description, 'type' => VTYPE_STRING),
        'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
        'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
    ));

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

ただし、PHPがオプションで引数にネイティブ型を受け入れる場合、同じメソッドが次のように記述されます。

public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
    // Check the arguments.
    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

どちらを書くのが短いですか?読みやすいのはどれですか?


1
オプションで、いくつかの動的型付け言語(Common Lispなど)で型を指定できます。
SKロジック

かなりの数の動的型付け言語は、型を強制的にキャストを使用して...
Trezoid

ある人はそうします。たとえば、Objective-Cは動的に型指定されますが、変数の型を宣言できます。期待する型を取得できない場合、コンパイラは警告を発行します。
ミパディ

1
Clojureは通常動的に型指定される言語の例ですが、オプションで「型ヒント」を使用して変数型を指定できます(これは通常、コンパイル時の型情報のパフォーマンス上の利点を得るために必要な場合にのみ行われます)
-mikera

1
Groovyは、型を指定できる動的型付け言語の別の例です。
エリックウィルソン

回答:


17

静的型付けのポイントは、型に関してプログラムが正しいことを静的に証明できることです(注:あらゆる意味で完全に正しいわけではありません)。全体に静的型システムがある場合、ほとんどの場合型エラーを検出できます。

部分的なタイプ情報しかない場合、タイプ情報が完全に発生するコールグラフの小さな部分のみをチェックできます。しかし、不完全なパーツのタイプ情報を指定するのに時間と労力を費やしましたが、それは役に立たないが、誤った安心感を与える可能性があります。

型情報を表現するには、過度に単純化できない言語の一部が必要です。すぐに、次のような情報intでは不十分であることがわかります。あなたのような何かしたいよList<Pair<Int, String>>それも、ジャワのではなく、単純な場合には十分に混乱することができますなど、その後、パラメトリック・タイプを、。

次に、静的エラーのみをチェックするのはばかげているため、変換フェーズ実行フェーズでこの情報を処理する必要があります。ユーザーは、タイプ制約が指定されていれば常に保持されることを期待します。動的言語はそのままでは速すぎず、そのようなチェックはパフォーマンスをさらに低下させます。静的言語は、一度しか実行しないため、型のチェックに多大な労力を費やすことがあります。動的言語ではできません。

ここで、これらすべての機能を追加して維持し、人々がオプションでこれらの機能を使用し、型エラーのごく一部しか検出しないようにするとします。努力する価値はないと思います。

動的言語のポイントは、非常に小さく、非常に順応性のあるフレームワークを持つことです。その中で、静的言語で行うとより複雑なものを簡単に実行できます。メタプログラミング、モック、テスト、コードの動的置換など。SmalltalkとLispはどちらも非常に動的であるため、ソースからビルドするのではなく、環境イメージを出荷するほど極端になりました。ただし、特定のデータパスがタイプセーフであることを確認する場合は、アサーションを追加して、さらに単体テストを記述します。


1
+1。ただし、テストでは特定の状況ではエラーが発生しないことが示されるだけです。(タイプ)エラーが不可能であることの証明の代替としては不十分です。
インゴ

1
@Ingo:確かに。しかし、動的言語は、比較的単純なアイデアを非常に高速に表現する、いじくり回しと迅速なプロトタイピングに最適です。防弾製品コードが必要な場合は、安定したコアコンポーネントを抽出した後、静的言語に切り替えることができます。
9000

1
@ 9000、それらが素晴らしいことは疑いありません。3つまたは4つのラメテストを書くことはそうではなく、型安全性を保証できないことを指摘したかっただけです
インゴ

2
@ 9000、真実、そして悪いニュースは、それでも事実上不可能です。HaskellやAgdaのコードでさえ、たとえば、ランタイムで使用されるライブラリが正しいという仮定に依存しています。そうは言っても、数千のLOCが数十個のソースコードファイルにまたがるプロジェクトでは、何かを変更できて、その変更が影響を与えるすべての行をコンパイラが指すことがわかっているのはとてもクールです。
インゴ

4
不十分に書かれたテストは、静的型チェックの代わりではありません。それらは劣っています。よく書かれたテストは、静的型チェックの代替ではありません。それらは優れています。
ラインヘンリヒズ

8

ほとんどの動的言語では、オブジェクトまたは値のタイプを少なくとも動的にテストできます。

また、いくつかの動的言語には静的型推論、チェッカー、および/またはエンフォーサがあります。

また、Perl 6は静的型付けを使用しオプションの型システムをサポートします。


しかし、結論としては、多くの人々は動的に型付けされているため、動的言語を使用しているため、オプションの静的型付けは非常に「うんざり」していると思います。また、他の多くの人々は、「非プログラマーが使いやすい」という理由で、主に寛容な性質の動的型付けの結果としてそれらを使用します。彼らにとって、オプションのタイピングは、彼らが理解できないか、使用することに煩わされないものです。

あなたが冷笑的ななら、オプションの静的型付けは両方の世界の最悪を提供すると言うことができます。静的なタイプの熱狂者にとって、すべての動的なタイプの失敗を防ぐことはできません。ダイナミックタイプのファンの場合、ストラップはきつく締められていませんが、それでもストレートジャケットです。


2
自分で型をチェックすることは、ほとんどの状況でほとんどのコミュニティによって眉をひそめられることに注意すべきです。オブジェクトの階層を処理するときは、多態性(具体的には、「アヒルの型付け」)を使用し、可能な場合は賢明な型に強制します。型を許可しても意味がない場合がいくつかありますが、多くの言語では、これらの場合のほとんどで例外が発生するため、型チェックはほとんど役に立ちません。

4
「人々は通常、動的に入力されるため動的言語を使用します」:JavaScriptは、ほとんどのブラウザでサポートされている唯一の言語であるため使用されます。PHPは人気があるため使用されます。
アルセニムルゼンコ

2

Javascriptはオプションの静的型付けを含めることを計画していましたが、多くの成熟した動的言語がそのように進んでいるようです。

その理由は、最初にコードを作成するときに、高速かつ動的に入力する必要があるためです。コードが安定して動作し、多くの用途がある場合は、設計をロックダウンしてエラーを減らします。(これはユーザーと開発者の両方にとって有益です。前者は呼び出しのエラーチェックを取得し、後者は偶発的に物事を壊さないためです。

私は通常、プロジェクトの開始時にあまりにも多くの型チェックを見つけますが、私が使用している言語に関係なく、ライフタイムの終わりには少なすぎます。


JavaScriptにオプションの静的型付けを含める計画については知りません。しかし、ActiveScriptほどひどくないことを願っています。JavaScriptとJavaの両方の最悪。
ハビエル

JS 4(またはECMAscript 4)で計画されていましたが、論争のためにそのバージョンは削除されました。同様の何かが将来、何らかの言語で現れると確信しています。(Pythonでは、デコレータを使用して並べ替えることができます。)
Macke

1
デコレータは、一種のアサーションである動的型チェックを追加します。Pythonで包括的な静的型チェックを取得することはできませんが、言語の極端なダイナミズムのために、どんなに一生懸命やろうとします。
9000

@ 9000:それは正しい。ただし、動的型チェックは悪いとは思いません(ただし、JS4の場合はアヒル型の比較が望ましいです)。特に単体テストと組み合わせた場合、デコレータの型指定はIDE / lint-checkersをより便利にサポートできます。標準化。
マッケ

もちろん悪いことではありません!これは道徳の問題ではありません。ある時点で、何らかの方法でタイプを「チェック」する必要があります。Cで*((double *)0x98765E)と記述すると、CPUがそれを実行し、0x98765Eが実際にdoubleへのポインターであるかどうかを確認します。
インゴ

2

Pythonオブジェクトに型があります。

オブジェクトを作成するときにタイプを指定します。

同時に、手動で型チェックを行うのではなく、場合によっては動的に型付けされた言語で変数の型を指定する選択肢があると便利です。

実際、Pythonでの手動の型チェックはほとんどの場合、時間とコードの無駄です。

Pythonで型チェックコードを記述することは、単に悪い習慣です。

不適切なタイプが悪意のあるソシオパスによって使用された場合、タイプが適切でない場合、Pythonの通常のメソッドは通常の例外を発生させます。

コードを記述しなくても、プログラムはで失敗しますTypeError

実行時に型を決定する必要がある非常にまれなケースがあります。

なぜそのような制限があるのですか?

「制限」ではないので、質問は実際の質問ではありません。


2
「Pythonオブジェクトには型があります。」- え、ほんと?perlオブジェクト、PHPオブジェクト、および世界の他のすべてのデータ項目と同じです。静的型と動的型の違いは、型がチェックされるとき、つまり型エラーが現れるときだけです。それらがコンパイラエラーとして表示される場合、それは静的型付けであり、ランタイムエラーとして表示される場合、それは動的です。
インゴ

@Ingo:説明をありがとう。問題は、C ++およびJavaオブジェクトをある型から別の型にキャストできるため、オブジェクトの型が多少不明瞭になるため、これらのコンパイラの「型チェック」も少し不明瞭になることです。Pythonの型チェックは、たとえ実行時であっても、それほど曖昧ではありません。また、質問は、動的に型付けされた言語には型がないと言っているようなものです。良いニュースは、よくある間違いをしないことです。
S.Lott

1
あなたは正しい、型キャスト(型変換とは対照的に、((double)42))静的型付けを覆します。型システムが十分に強力でない場合に必要です。Java 5より前は、Javaにはパラメーター化された型がなかったため、型キャストなしでは生きられませんでした。今日でははるかに優れていますが、型システムには、より高いランクの多型は言うまでもなく、より高い種類の型がまだありません。動的に型付けされた言語は、あまりにも狭い型システムから1つを解放するため、正確にフォロワーを楽しんでいる可能性が十分にあると思います。
インゴ

2

ほとんどの場合、少なくともあなたが提案している詳細レベルでなくてもかまいません。PHPでは、使用する演算子により、引数が何であるかが完全に明確になります。文字列を予期する操作に配列を渡す場合でも、PHPは可能な限り値をキャストしますが、キャストは常に意味があるとは限らないため、時々奇妙な結果が得られますが、設計上の見落としです。そして、これはまさに型チェック有用な場所です)。あなたは、整数追加する場合それ以外は、それは問題ではありません1し、5または文字列"1""5"、使用しているという単なる事実を-+演算子は、引数を数値として扱いたいことをPHPに通知し、PHPはそれに従います。興味深い状況は、MySQLからクエリ結果を受け取ったときです。多くの数値は単に文字列として返されますが、数値として扱うときはPHPがそれらをキャストするため気付かないでしょう。

Pythonはその型について少し厳密ですが、PHPとは異なり、Pythonは最初から例外があり、一貫して使用しています。「許可よりも許しを求める方が簡単」というパラダイムは、型チェックなしで操作を実行し、型が意味をなさない場合に発生する例外に依存することを示唆しています。私が考えることができるこの唯一の欠点は、時々、型があなたが期待するものと一致しないことを見つけることがありますが、理由を見つけるのは退屈な場合があります。

考慮すべきもう1つの理由があります。動的言語にはコンパイル段階ありません。型制約がある場合でも、単にコンパイル時間がないため、実行時にのみ起動できます。とにかくチェックが実行時エラーにつながる場合、それに応じてそれらをモデル化するのがはるかに簡単です:明示的なチェック(is_XXX()PHPやtypeofjavascriptなど)として、または例外をスローすること(Pythonのように)。機能的には、同じ効果があります(型チェックが失敗すると実行時にエラーが通知されます)が、他の言語のセマンティクスとの統合性が向上しています。型エラーを、動的言語の他の実行時エラーと根本的に異なるものとして扱うことは、単に意味をなしません。


0

Haskellに興味があるかもしれません-タイプシステムはコードからタイプを推測し、タイプも指定できます。


5
Haskellは素晴らしい言語です。それはどういうわけか動的言語の反対です。型を記述するのに多くの時間を費やし、通常、型を理解するとプログラムが動作します:)
9000

@ 9000:確かに。コンパイルすると、通常は機能します。:)
マッケ

@Macke-の異なる値 通常もちろん。:-)私にとって、型システムと機能パラダイムの最大の利点は、他の場所で指摘したように、どこかで変更が静かに他の依存コードに影響を与えるかどうかを気にする必要がないことです-コンパイラは型エラーを指摘します可変状態は存在しません。
インゴ

0

他の答えが示唆しているように、プログラミング言語を実装する際のタイピングには2つのアプローチがあります。

  1. すべての変数と関数が型に使用するものをプログラマーに教えてもらいます。理想的には、型指定が正確であることも確認します。そうすれば、それぞれの場所にどんな種類の物があるかを知っているので、適切なものがそこにあると想定し、その種類を直接実装するために使用するデータ構造を使用するコードを書くことができます。
  2. 変数に格納され、関数に渡され、関数から返される値に型インジケータを添付します。これは、変数や関数が参照するオブジェクトに実際に属しているため、プログラマーが変数や関数の型を指定する必要がないことを意味します。

どちらのアプローチも有効であり、どちらを使用するかは、パフォーマンスなどの技術的考慮事項と、言語のターゲット市場などの政治的理由に一部依存します。


0

まず第一に、動的言語は主に使いやすさのために作成されます。既に述べたように、型変換を自動的に実行し、オーバーヘッドを減らすことは本当に良いことです。ただし、同時にパフォーマンスの問題もありません。

パフォーマンスを気にしない場合は、動的言語に固執することができます。たとえば、プログラムで多くの型変換を実行する必要がある場合、JavaScriptの実行は遅くなりますが、コードの行数を減らすのに役立ちます。

また、プログラマーが型を指定できる動的言語もあります。たとえば、GroovyはJVMで実行される有名な動的言語の1つです。そして、最近でも非常に有名です。GroovyのパフォーマンスはJavaと同じであることに注意してください。

お役に立てば幸いです。


-1

そうするだけでは意味がありません。

どうして?

DTLの型システムは、コンパイル時に型を決定できないほど正確であるためです。したがって、コンパイラーは、指定されたタイプが意味をなすかどうかさえチェックできませんでした。


1
どうして?どのタイプを期待するかについてコンパイラーにヒントを与えることは完全に理にかなっています。型システムの制約と矛盾することはありません。
SKロジック

1
SKロジック:動的に型指定される場合、すべての関数/メソッド/操作が「動的」、「任意」などのオブジェクトを取り、「動的」、「任意」を返すことを意味する場合、一般に特定の値を伝える方法はありませんたとえば、常に整数になります。したがって、ランタイムコードは、型がそもそも「動的」であるかのように、とにかく非整数をチェックする必要があります。これは、静的型システムの機能です。特定の変数、フィールド、またはメソッドの戻り値が常に特定の型であることを証明できます。
インゴ

@Ingo、いいえ、方法があります。たとえば、Common Lispでどのように実装されているかをご覧ください。これは特にローカル変数に役立ちます。すべてのタイピングヒントを導入することで、パフォーマンスを劇的に向上させることができます。
SKロジック

@ SK-logic:CLで型エラーがいつ、どのように検出されるか教えていただけますか?とにかく、@ MainMaは彼/彼女の質問で現状を非常にうまく要約しました:それは「純粋に」動的言語に期待できることです。
インゴ

@Ingo、型が静的に正当性を証明するためにのみ有用であると思わせる理由は何ですか?Cのような、チェックされていない型キャストを持っている言語でさえも当てはまりません。動的言語の型注釈は、パフォーマンスを改善したり、具体的な数値表現を指定したりするコンパイラのヒントとして主に役立ちます。ほとんどの場合、注釈はコードのセマンティクスを変更すべきではないことに同意します。
SKロジック

-1

Goを見てください。表面上は静的に型付けされていますが、これらの型は本質的に動的なインターフェイスである場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.