また、一方が他方を意味するのでしょうか。
強く型付けされた言語と静的に型付けされた言語の違いは何ですか?
静的に型付けされた言語には、実装時にコンパイラーまたはコンパイラーによってコンパイル時にチェックされる型システムがあります。型チェックは一部のプログラムを拒否し、通常、チェックに合格したプログラムにはいくつかの保証が付いています。たとえば、コンパイラは、浮動小数点数で整数演算命令を使用しないことを保証します。
「強く型付けされた」とはどういう意味かについては本当の合意はありませんが、専門文献で最も広く使用されている定義は「強く型付けされた」言語であり、プログラマーは型システムによって課せられた制限を回避することはできません。この用語はほとんどの場合、静的に型付けされた言語を表すために使用されます。
静的に型付けされるのとは反対の「動的に型付けされる」、つまり
たとえば、動的に型指定される言語である Lua には、文字列型、数値型、ブール型などがあります。 Luaでは、すべての値は exactly 1つの型に属しますが、これはすべての動的型付け言語の要件ではありません。 Luaでは、2つの文字列を連結することはできますが、文字列とブール値を連結することはできません。
「強く型付け」の反対は「弱い型付け」です。つまり、型システムを回避できます。ポインター型は、キャストするだけで他のポインター型に変換できるため、Cは弱い型付けで有名です。 Pascalは強く型付けすることを意図していましたが、デザインの見落とし(タグなしバリアントレコード)により型システムに抜け穴が生じたため、技術的には型付けが弱いです。真に強く型付けされた言語の例には、CLU、Standard ML、Haskellが含まれます。実際、標準MLは、言語が広く展開された後に発見された型システムの抜け穴を削除するために、いくつかの改訂を受けました。
全体として、「強い」と「弱い」について話すのはそれほど有用ではないことがわかりました。型システムに抜け穴があるかどうかは、抜け穴の正確な数と性質、それらが実際に発生する可能性、および抜け穴を悪用した場合の結果ほど重要ではありません。実際には、「強い」および「弱い」という用語を完全に避けるのが最善です。
アマチュアはしばしば「静的」および「動的」と混同します。
どうやら「弱いタイピング」は、暗黙の変換の相対的な優先度または欠如について話すために使用される人もいます。
専門家は、用語の意味を正確に同意することはできません。
全体として、聴衆に知らせたり啓発したりすることはまずありません。
悲しい真実は、型システムに関しては、「強い」と「弱い」は技術的な意味で普遍的に合意されていないということです。型システムの相対的な強さについて議論したい場合、保証が何であり、提供されていないかを正確に議論する方が良いです。たとえば、尋ねるべき良い質問は次のとおりです。「特定の型(またはクラス)のすべての値は、その型のコンストラクターの1つを呼び出すことによって作成されたことが保証されていますか?」 Cでは、答えはノーです。 CLU、F#、およびHaskellでは、yesです。 C++についてはわかりません。知りたいです。
対照的に、静的タイピングは、プログラムが実行される前にチェックされるを意味し、プログラムは開始前に拒否される場合があります。 動的タイピングは、 values のタイプがチェックされることを意味します /実行中操作により、実行時にプログラムが停止したり、エラーが発生したりする場合があります。静的型付けの主な理由は、このような「動的型エラー」が発生する可能性のあるプログラムを除外することです。
一方が他方を暗示していますか?
学問的なレベルでは、いいえ。「強い」という言葉は実際には何も意味しないからです。しかし、実際には、人々はほとんど常に次の2つのことのいずれかを行います。
彼らは「誤って」「強い」と「弱い」を使用して「静的」と「動的」を意味し、その場合、彼らは「誤って」「強く型付けされた」と「静的に型付けされた」を交互に使用しています。
静的型システムのプロパティを比較するために、「強い」と「弱い」を使用します。誰かが「強い」または「弱い」動的型システムについて話すのを聞くのは非常にまれです。実際には型システムをまったく持たないFORTHを除き、型システムを破壊できる動的型付け言語は考えられません。定義により並べ替えると、これらのチェックは実行エンジンに組み込まれ、すべての操作が実行される前に健全性がチェックされます。
いずれにせよ、ある人が「強く型付けされた」言語を呼び出すと、その人は静的に型付けされた言語について話している可能性が非常に高いです。
これはよく誤解されているので、それを片付けましょう。
静的型指定は、型が変数にバインドされる場所です。型はコンパイル時にチェックされます。
動的タイピングは、タイプが値にバインドされる場所です。型は実行時にチェックされます。
例えばJavaでは:
String s = "abcd";
s
は「永遠に」String
になります。その寿命の間に、それは異なるString
sを指すかもしれません(s
はJavaにおける参照であるため)。それは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
に強制変換されるため、実際に条件は真になります。解決策は、暗黙の変換を避けるために===
の代わりに==
を使用することです。
この例は、暗黙の型変換と動的型付けの組み合わせがプログラマーをどのように誤解させる可能性があるかを示しています。
それをRubyと比較してください。
val = "abc" + 123
rubyではオブジェクト123は暗黙的にNOTなので、これは実行時エラーです。たまたまそれが+
メソッドに渡されるという理由だけで変換されます。 Rubyでは、プログラマは変換を明示的にする必要があります。
val = "abc" + 123.to_s
PHPとRubyを比較すると良い例です。どちらも動的に型付けされた言語ですが、PHPには暗黙的な変換がたくさんあり、Rubyは(おそらくあなたがそれに慣れていないのであれば驚くべきことに)ありません。
ここで重要なのは、静的/動的軸が強/弱軸から独立しているということです。強いタイピングと弱いタイピングはあまり明確に定義されていないだけでなく、強いと弱いが何を意味しているのかについて真のコンセンサスがないため、人々はおそらくそれらを混同します。このため、強/弱タイピングは、黒や白ではなく、はるかに灰色の濃淡で表現されます。
それであなたの質問に答えるために:これを見るためのもう一つの見方はほとんど正しいですタイプ安全。
その理由は、静的型付け言語の変数は宣言しなければならない型を持ち、コンパイル時にチェックできるからです。強く型付けされた言語は実行時に型を持つ値を持ち、プログラマが動的チェックなしに型システムを破壊することは困難です。
しかし、言語は静的/強い、静的/弱い、動的/強い、または動的/弱いのいずれかであることを理解することが重要です。
どちらも2つの異なる軸上の極です。
厳密に型指定されたは、aがある型から別の型に自動的に変換されないことを意味します。弱い型付けは反対です。Perlは自動的にint "123"
に変換することで、数値コンテキストで123
のような文字列を使用できます。 pythonのような強く型付けされた言語はこれをしません。
静的型指定は、コンパイラがコンパイル時に各変数の型を判断することを意味します。動的型付き言語は実行時に変数の型を理解するだけです。
強く型付けされているとは、型間の変換の間に制限があることを意味します。静的型とは、型が動的ではないことを意味します。一度作成された変数の型は変更できません。
データの強制変換は、構文糖があることがあるため、必ずしも型付けが弱いという意味ではありません。
上の例では、Javaが弱く型付けされています。
String s = "abc" + 123;
それは本当にやっているので弱くタイプされた例ではありません:
String s = "abc" + new Integer(123).toString()
あなたが新しいオブジェクトを構築しているならば、データ強制も弱くタイプされません。 Javaは、弱い型付けの非常に悪い例です(そして、よく反映されている言語は、ほとんど型付けされていないでしょう)。なぜなら、言語の実行時は型が何であるかを常に知っているからです(例外はネイティブ型かもしれません)。
これはCとは異なります。Cは、弱い型指定の最も良い例の1つです。ランタイムは、4バイトが整数、構造体、ポインタ、または4文字であるかどうかわかりません。
この言語の実行時は、その型の弱い打ち合わせがされているかどうかは、実際には正しい意見であるかどうかを実際に定義しています。
EDIT:さらに考えた後、ランタイムシステムで厳密に型指定されたシステムになるようにすべての型を具体化する必要はないので、これは必ずしも当てはまりません。 HaskellとMLは、完全な静的解析を行っているため、ランタイムから型情報を省略する可能性があります。
強い型付けはおそらく、変数が明確に定義された型を持ち、式の中で異なる型の変数を組み合わせることについて厳密な規則があることを意味します。たとえば、Aが整数でBが浮動小数点数の場合、A + Bに関する厳密な規則は、Aが浮動小数点数にキャストされ、結果が浮動小数点数として返されることです。 Aが整数でBが文字列の場合、厳密な規則として、A + Bは無効である可能性があります。
静的型付けとは、おそらく型がコンパイル時に割り当てられ(またはコンパイルされていない言語の場合はそれと同等の)、プログラムの実行中に変更できないことを意味します。
これらの分類は相互に排他的ではないことに注意してください。実際、これらの分類は頻繁に一緒に発生すると予想されます。強く型付けされた多くの言語も静的型付けされています。
そして、私が「おそらく」という言葉を使うとき、それはこれらの用語の普遍的に受け入れられた定義がないためです。あなたはすでにこれまでの答えから見てきたように。
一方は他方を意味しません。言語が静的に型付けされることは、すべての変数の型が既知であるか、コンパイル時に推論されることを意味します。
強い型付き言語では、ある型を別の型として使用することはできません。 Cは弱い型付けの言語であり、強い型付けの言語では許可されていないものの良い例です。 Cでは、間違った型のデータ要素を渡すことができ、それは文句を言いません。強く型付けされた言語ではできません。
答えはすでに上で与えられています。強い対週と静的対動的の概念を区別しようとしています。
強い型付け:ある型から別の型に自動的に変換されません
GoやPythonのように強く型付けされた言語 "2" + 8は "型強制"を許さないので型エラーを起こします。
弱く(緩やかに)型付けされている:自動的にある型から別の型に変換されるでしょう: JavaScriptやPerlのような弱く型付けされた言語はエラーを投げません10。
Perlの例:
my $a = "2" + 8;
print $a,"\n";
Main.plに保存してPerl main.pl
を実行すると、出力10が得られます。
プログラミングでは、progammerは変数の型がチェックされる点に関して静的型と動的型を定義します。静的型付き言語はコンパイル時に型チェックが行われる言語ですが、動的型付き言語は実行時に型チェックが行われる言語です。
これはどういう意味ですか?
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が動的に型付けされているからです。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