強く型付けされた言語と静的に型付けされた言語の違いは何ですか?


回答:


540

強く型付けされた言語と静的に型付けされた言語の違いは何ですか?

静的に型付けされた言語の型システムは、コンパイル時に実装(コンパイラーまたはインタープリター)によってチェックされます。型チェックは一部のプログラムを拒否し、チェックに合格したプログラムは通常、いくつかの保証が付いています。たとえば、コンパイラーは、浮動小数点数に対して整数演算命令を使用しないことを保証します。

「強く型付けされた」が何を意味するかについての実際の合意はありませんが、専門文献で最も広く使用されている定義は、「強く型付けされた」言語では、プログラマーが型システムによって課された制限を回避することができないということです。この用語は、ほとんどの場合、静的型付け言語を表すために使用されます。

静的vs動的

静的型付けの反対は「動的型付け」です。つまり、

  1. 実行時に使用される値は、タイプに分類されます。
  2. このような値の使用方法には制限があります。
  3. これらの制限に違反すると、違反は(動的)タイプのエラーとして報告されます。

たとえば、動的に型付けされる言語であるLuaには、文字列型、数値型、ブール型などがあります。Luaのでは、すべての値がに属し、正確に一つのタイプが、これは、すべての動的型付け言語の要件ではありません。Luaでは、2つの文字列を連結することは許可されていますが、文字列とブール値を連結することは許可されていません。

強いvs弱い

「強く型付けされた」の反対は「弱い型付け」です。つまり、型システムを回避できます。ポインタ型はキャストするだけで他のポインタ型に変換できるため、Cの型は弱いことで有名です。Pascalは強く型付けされることを意図していたが、設計の見落とし(タグなしのバリアントレコード)により型システムに抜け穴ができたため、技術的には型付けが弱い。真に強く型付けされた言語の例には、CLU、標準ML、Haskellなどがあります。標準MLは、言語が広く導入された後に発見された型システムの抜け穴を取り除くために、実際にいくつかの改訂を受けました。

ここで何が起こっているのですか?

全体として、「強い」と「弱い」について話すことはそれほど有益ではないことがわかります。型システムに抜け穴があるかどうかは、抜け穴の正確な数と性質、実際に出現する可能性、および抜け穴を悪用した場合の結果よりも重要ではありません。実際には、「強い」と「弱い」という用語を完全に避けることが最善です。

  • アマチュアはしばしばそれらを「静的」および「動的」と融合させます。

  • どうやら「弱い型付け」は、暗黙の変換の相対的な有病率または不在について話すために一部の人によって使用されています。

  • 専門家は、用語が何を意味するのか正確に合意することはできません。

  • 全体として、視聴者に情報を伝えたり、啓蒙したりすることはほとんどありません。

悲しい真実は、型システムに関しては、「強い」と「弱い」は技術的な意味で普遍的に合意されていないということです。 型システムの相対的な強さを議論したい場合は、何が保証されて何が提供されないかを正確に議論する方が良いです。たとえば、次のような質問をすることをお勧めします。「特定の型(またはクラス)のすべての値は、その型のコンストラクターの1つを呼び出すことによって作成されたことが保証されていますか?」Cでは答えはノーです。CLU、F#、およびHaskellでは、それはイエスです。C ++についてはわかりません。知りたいのですが。

対照的に、静的型付けとは、プログラムが実行される前にチェックされ、プログラムが開始される前に拒否される可能性があることを意味します。 動的型付けとは、実行の型がチェックされることを意味します。型付けが適切ないと、プログラムが停止したり、実行時にエラーを通知したりすることがあります。静的型付けの主な理由は、そのような「動的型エラー」が発生する可能性のあるプログラムを除外するためです。

一方が他方を示唆していますか?

教育レベルでは、「強い」という言葉は実際には何の意味もないので、違います。しかし実際には、人々はほとんど常に次の2つのことのいずれかを行います。

  • 彼らは(誤って)「静的」と「動的」を意味する「強い」と「弱い」を使用します。その場合、彼らは(誤って)「強く型付けされた」と「静的に型付けされた」を交換可能に使用しています。

  • 静的型システムのプロパティを比較するために、「強い」と「弱い」を使用します。「強い」または「弱い」動的型システムについて誰かが話すのを聞くのは非常にまれです。型システムがまったくないFORTHを除いて、動的に型付けされた言語で型システムを破壊できるとは思えません。定義上、これらのチェックは実行エンジンに組み込まれ、すべての操作は実行前に正常性がチェックされます。

どちらの方法でも、人が「強く型付けされた」言語を呼び出す場合、その人は静的に型付けされた言語について話している可能性が非常に高いです。


3
@アダム:明らかに正しいので賛成できない:) Cletusの回答には非常に多くの誤解が含まれているため(私はそれらの最悪のものを編集しましたが)、1つの音節の言葉ですべてを綴るように強いられました...
Norman Ramsey

1
まあ私はあなたに賛成しました:)「コンパイル」という言葉でさえ、動的言語を実行している今日のVMでは明確な言葉ではありません。技術的には、JavaとC#は両方とも2回コンパイルされ(JIT)、両方とも型分析を行います。.NET vmで実行されているJavaScriptのような言語は、VMのためにタイプセーフである可能性があります。
Adam Gent

2
私は今とても混乱しています!さて、アリーナの素晴らしい剣闘士、私のような貧しい魂は、次の簡単な理解で行くことができますか?1.Static:Valuesは実行時ではなくコンパイル時に型に関連付けられます.2.Dynamic:Valuesは実行時に型に関連付けられるため、実行時に値の型が変更される可能性があるため、型キャストに関連する問題が発生しやすくなります実行時。3.強い/弱い:忘れる!これらは専門用語ではなく、単に悪い命名法です。それは人が話している文脈に依存します。この簡単な理解で私の人生を続けることができますか?:(
Saurabh Patil 2014

「特定のタイプ(またはクラス)のすべての値は、そのタイプのコンストラクターの1つを呼び出すことによって作成されたことが保証されていますか?」Cでは答えはノーです。これがCで発生する状況の例を誰かが提供できますか?構造体へのポインタのキャストが含まれていると思いますか?
corazza 2014

強い型付けと弱い型付け:そのような分類はありません。
ラウル

247

これは誤解されることが多いので、片付けておきます。

静的/動的型付け

静的型付けは、型が変数にバインドされる場所です。タイプはコンパイル時にチェックされます。

動的型付けは、型が値にバインドされる場所です。タイプは実行時にチェックされます。

たとえばJavaでは次のようになります。

String s = "abcd";

s「永久に」になりますString。その存続期間中は、異なるを指す場合があります(Javaでの参照であるStringためs)。null値を持つ場合がありますが、Integerまたはを参照することはありませんList。それは静的型付けです。

PHPの場合:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

それは動的なタイピングです。

強い/弱いタイピング

(アラートを編集!)

強いタイピングとは、広く合意された意味のないフレーズです。この用語を静的型付け以外のことを意味するために使用するほとんどのプログラマーは、コンパイラーによって強制される型の規律があることを意味するためにこれを使用します。たとえば、CLUには強力な型システムがあり、タイプによって提供されるコンストラクターを使用しない限り、クライアントコードは抽象型の値を作成できません。Cはやや強力な型システムを持っていますが、プログラムは常にあるポインタ型の値を別のポインタ型の値にキャストできるため、ある程度「破壊」される可能性があります。したがって、たとえばCでは、によって返された値を取り、malloc()陽気ににキャストすることFILE*ができ、コンパイラーはユーザーを止めようとはしません。

(元の答えは、「実行時に型を変更しない」という値について何かを述べていました。私は多くの言語デザイナーやコンパイラー作成者を知っており、実行時に型を変更する値について話している人は知りません。これは「強い更新の問題」として知られているシステム)

弱いタイピングは、コンパイラーが型付けの規律を強制しないこと、またはおそらく強制が簡単に覆される可能性があることを意味します。

この回答のオリジナルは、弱い型付けと暗黙的な変換を融合させました(「暗黙的なプロモーション」とも呼ばれます)。たとえば、Javaの場合:

String s = "abc" + 123; // "abc123";

これは、暗黙的なプロモーションの例のコードです。123は、と連結される前に暗黙的に文字列に変換されます"abc"。Javaコンパイラがそのコードを次のように書き換えていると主張できます。

String s = "abc" + new Integer(123).toString();

古典的なPHPの「次で始まる」問題を考えてみます。

if (strpos('abcdef', 'abc') == false) {
  // not found
}

ここでのエラーは、strpos()0である一致のインデックスを返すことです。0はブール値に強制変換されるfalseため、条件は実際にはtrueです。解決策は、暗黙的な変換を回避する===代わりにを使用することです==

この例は、暗黙の変換と動的型付けの組み合わせがプログラマを迷わせる方法を示しています。

Rubyと比較してください。

val = "abc" + 123

Rubyではオブジェクト 123がたまたまメソッドに渡されただけで暗黙的に変換されないため、これはランタイムエラー+です。Rubyでは、プログラマは変換を明示的にする必要があります。

val = "abc" + 123.to_s

PHPとRubyの比較は、ここでの良い例です。どちらも動的に型付けされた言語ですが、PHPには多くの暗黙の変換があり、Ruby(おそらく、それに慣れていない場合は驚くべきこと)にはありません。

静的/動的vs強/弱

ここでのポイントは、静的/動的軸が強軸/弱軸から独立していることです。強い型と弱い型が明確に定義されていないだけでなく、強い型と弱い型が何を意味するかについて正確なコンセンサスがないため、人々はおそらくそれらを混乱させます。このため、強い/弱いタイピングは、黒や白ではなく、灰色の濃淡で行われます。

だからあなたの質問に答える:これを見るのがほとんど正しい別の方法は、静的型付けはコンパイル時の型安全であり、強い型付けはランタイム型安全であると言うことです。

これは、静的に型付けされた言語の変数には、宣言する必要のある型があり、コンパイル時にチェックできるためです。強く型付けされた言語には、実行時に型を持つ値があり、プログラマが動的チェックなしに型システムを破壊することは困難です。

ただし、言語は静的/強力、静的/弱、動的/強力、動的/弱のいずれかになる可能性があることを理解することが重要です。


$ sが整数または文字列であると言う代わりに、型が変数$ sではなく「abcd」または1234に関連付けられていると言った方がよいでしょう。
Srinivas Reddy Thatiparthy 2010

明確な例による優れた回答。しかし、人々が強い/静的なものを双子の概念のペアとして尋ねる理由についての混乱を完全に扱っているわけではないと思います。たとえば、OPの「静的型付けは暗黙的に強い型付けをしますか?」という表現です。あなたの答えは彼らの独立を強調しています。強いものがしばしば静的とペアになっている理由の明確化を続けるために、Norman Ramseyの以前の答えは非常に良いです: stackoverflow.com/questions/376611/…
JasDev

1
"abc" + 123Rubyのコンパイルエラーではなく、実行時エラーです。コンパイルエラーの場合、ルビは静的に型付けされます。
sepp2k 2010

弱い型付けの例は改善する必要がありますが(私の回答を参照)、それ以外の点では優れたフォーマットです。
アダム・ゲント

私の意見では、強い対弱いtypginはこれです:強い: "c" + True =ランタイムエラーまたはコンパイル時エラー。弱: "c" + True = "b"または "d"すべてが生のバイトとして扱われるため。強:C#、Ruby、C ++弱:アセンブリ、C(暗黙のvoidポインターによる)
ジョナサンアレン

17

どちらも2つの異なる軸上の極です。

  • 強く型付けされたものと弱い型付けされたもの
  • 静的型付けと動的型付けの比較

強く型付けされたとは、aがある型から別の型に自動的に変換されないことを意味します。弱い型付けはその逆です。Perlは、文字列"123"を自動的にintに変換することにより、数値コンテキストのように使用できます123。Pythonのような強く型付けされた言語はこれを行いません。

静的型付けとは、コンパイラがコンパイル時に各変数の型を計算することを意味します。動的に型付けされた言語は、実行時に変数の型のみを把握します。


6
私は反対しなければなりません。強く型付けされた言語は、実行時に型が何であるかを知っている言語です。弱く型付けされた言語は、アセンブリが好きではない言語です。あなたの例は、3番目の軸、「暗黙的な変換と明示的な変換」にあります。
ジョナサンアレン

1
実際には、私はジョナサンに同意しますが、完全な静的分析を行い、キャストを許可しない場合は、実行時に型を強く型付けする必要はありません。(私の編集した回答を参照してください)。
Adam Gent、

1
Pythonは動的に型付けされた言語と強く型付けされた言語の例です
-MaRoBet

12

強く型付けされているとは、型間の変換の間に制限があることを意味します。静的型付けとは、型が動的でないことを意味します。一度作成された変数の型を変更することはできません。


これを実証するには:強く型付けされた言語では、 "5" == 5を比較してtrueにすることはできません。文字列は整数ではありません。私の記憶が役立った場合、ほとんどの最新のスクリプト言語は強く動的に型付けされます。Tcl / Tkは弱い型付けです-すべてを文字列として扱うことができます。
リトルボビーテーブル

弱く型付けされた言語のボビー、 "5" == 5は0x35 == 0x05として読み取られます。つまり、すべてが生のバイトとして扱われます。
ジョナサンアレン

私はあなたたち二人に同意しなければなりません。ルアを取る; あなたは「5」== 5比較することができ、それはfalseを返します、しかし迅速な変換が「5」+ 0行くことによって行うことができます
RCIX

12

Data Coercionは必ずしも弱い型付けを意味するわけではありません。それは、そのシンタクシカルな砂糖が時々あるからです。

上記のJavaが弱い型付けの例

String s = "abc" + 123;

それは本当にやっているので、弱く型付けされた例ではありません:

String s = "abc" + new Integer(123).toString()

新しいオブジェクトを構築する場合も、データ型変換は弱く型付けされません。Javaは、弱く型付けされた非常に悪い例です(そして、適切に反映されている言語は、弱く型付けされていない可能性が高いです)。言語のランタイムは型が何であるかを常に知っているからです(例外はネイティブ型かもしれません)。

これはCとは異なります。Cは弱い型付けの最も良い例の1つです。ランタイムは、4バイトが整数、構造体、ポインター、または4文字であるかどうかを知りません。

言語のランタイムは、弱く型付けされているかどうかを本当に定義します。

編集: さらに考えた後、ランタイムは厳密に型指定されたシステムになるためにランタイムシステムですべての型を具体化する必要がないため、これは必ずしも正しくありません。HaskellとMLには完全な静的分析があり、ランタイムから型情報が省略される可能性があります。


よく知られていない例としては、Bの方が良いでしょう。
トム・ホーティン-タックライン2010

Javascriptもやや弱い型ですが、型が非常に少なく、新しい型を実際に構築できないためです。
アダム・ゲント

9

回答はすでに上記で与えられています。強力な概念と週の概念、静的な概念と動的な概念を区別しようとします。

強く型付けされたVS弱い型付けとは何ですか?

強く型付け:ある型から別の型に自動的に変換されません

GoまたはPythonでは、厳密に型指定された言語のように、「2」+ 8は「型強制」を許可しないため、型エラーが発生します。

弱く(ゆるく) 型付け:ある型から別の型に自動的に変換されます: JavaScriptやPerlなどの弱く型付けされた言語はエラーをスローせず、この場合、JavaScriptは「28」となり、perlは10になります。

Perlの例:

my $a = "2" + 8;
print $a,"\n";

それをmain.plに保存して実行します perl main.plすると、出力10が得られます。

静的VS動的タイプとは何ですか?

プログラミングでは、プログラマーは、変数タイプがチェックされるポイントに関して静的型付けと動的型付けを定義します。静的型付き言語は、型チェックがコンパイル時に行われる言語であり、動的型付き言語は、型チェックが実行時に行われる言語です。

  • 静的:実行前にチェックされる型
  • 動的:実行中にオンザフライでチェックされる型

これはどういう意味ですか?

Goでは、実行前に入力されたチェックを行います(静的チェック)。つまり、実行中のコードを変換して型チェックするだけでなく、すべてのコードをスキャンし、コードが実行される前に型エラーがスローされます。例えば、

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

このファイルをmain.goに保存して実行すると、コンパイル失敗のメッセージが表示されます。

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

ただし、このケースはPythonでは無効です。たとえば、次のコードブロックは最初のfoo(2)呼び出しに対して実行され、2番目のfoo(0)呼び出しに対して失敗します。これは、Pythonが動的に型付けされているため、実行されているコードの変換と型チェックのみを行うためです。elseブロックはfoo(2)では決して実行されないため、「2」+ 8は決して見られず、foo(0)呼び出しではそのブロックを実行しようとして失敗します。

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

次の出力が表示されます

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects

8

一方は他方を意味しません。言語を静的にするには型付けされるということは、すべての変数の型がコンパイル時に既知または推論されることを意味します。

強く型付けされた言語を使用すると、別のように、1つのタイプを使用することはできません。Cは弱く型付けされた言語であり、強く型付けされた言語が許可しないものの良い例です。Cでは、間違ったタイプのデータ要素を渡すことができ、文句はありません。強く型付けされた言語ではできません。


7

強い型付けとは、おそらく変数が明確に定義された型を持ち、式で異なる型の変数を結合することに関して厳しい規則があることを意味します。たとえば、Aが整数でBが浮動小数点の場合、A + Bに関する厳密な規則は、Aが浮動小数点にキャストされ、結果が浮動小数点として返されることです。Aが整数でBが文字列である場合、厳密な規則はA + Bが無効であることです。

静的型付けとは、おそらく型がコンパイル時に割り当てられ(またはコンパイルされていない言語では同等)、プログラムの実行中に変更できないことを意味します。

これらの分類は相互に排他的ではないことに注意してください。実際、これらは一緒に頻繁に発生すると予想されます。多くの強く型付けされた言語も静的に型付けされます。

そして、私が「おそらく」という言葉を使用するのは、これらの用語の普遍的に受け入れられている定義がないためです。あなたはこれまでの答えからすでに見てきたように。

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