web-dev-qa-db-ja.com

タイプセーフとは何ですか?

「タイプセーフ」とはどういう意味ですか?

227
Razin

型の安全性とは、コンパイル中にコンパイラが型を検証し、間違った型を変数に割り当てようとするとエラーがスローされることを意味します。

いくつかの簡単な例:

// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";

これはメソッド引数にも適用されます。明示的な型を渡すためです。

int AddTwoNumbers(int a, int b)
{
    return a + b;
}

私はそれを使用してそれを呼び出そうとした場合:

int Sum = AddTwoNumbers(5, "5");

文字列( "5")を渡しているため、コンパイラはエラーをスローし、整数を予期しています。

Javascriptなどの緩く型付けされた言語では、次のことができます。

function AddTwoNumbers(a, b)
{
    return a + b;
}

このように呼び出すと:

Sum = AddTwoNumbers(5, "5");

Javascriptは5を自動的に文字列に変換し、「55」を返します。これは、文字列の連結に+記号を使用するjavascriptによるものです。タイプを認識するには、次のようなことをする必要があります。

function AddTwoNumbers(a, b)
{
    return Number(a) + Number(b);
}

または、おそらく:

function AddOnlyTwoNumbers(a, b)
{
    if (isNaN(a) || isNaN(b))
        return false;
    return Number(a) + Number(b);
}

このように呼び出すと:

Sum = AddTwoNumbers(5, " dogs");

Javascriptは5を自動的に文字列に変換し、追加して「5 dogs」を返します。

すべての動的言語がjavascriptほど寛容であるわけではありません(実際、動的言語は暗黙のルーズ型言語を意味するものではありません(Pythonを参照))、実際には無効な型キャストで実行時エラーが発生します。

便利ではありますが、簡単に見落とされる可能性があり、実行中のプログラムをテストすることによってのみ特定される多くのエラーが発生します。個人的には、その間違いを犯したかどうかをコンパイラーに教えてもらいたいです。

さて、C#に戻ります...

C#は covariance と呼ばれる言語機能をサポートします。これは基本的に、基本型を子型に置き換えることができ、エラーが発生しないことを意味します。たとえば、

 public class Foo : Bar
 {
 }

ここでは、Barをサブクラス化する新しいクラス(Foo)を作成しました。メソッドを作成できるようになりました:

 void DoSomething(Bar myBar)

また、FooまたはBarを引数として使用して呼び出すと、エラーが発生することなく両方が機能します。これは、Barの子クラスがBarのインターフェースを実装することをC#が知っているために機能します。

ただし、逆を行うことはできません。

void DoSomething(Foo myFoo)

この状況では、Barはこのメソッドに渡すことができません。コンパイラがBarがFooのインターフェイスを実装していることを知らないためです。これは、子クラスが親クラスとは大きく異なる可能性があるためです(通常はそうなります)。

もちろん、今私は深い終わりを脱し、元の質問の範囲を超えていますが、知っておくべきすべてのものがあります:)

225
FlySwat

型の安全性を、静的/動的型付けまたは強い/弱い型付けと混同しないでください。

タイプセーフ言語とは、データに対して実行できる操作が、データのタイプによって容認される操作のみである言語です。つまり、データのタイプがXで、Xが操作yをサポートしていない場合、言語はy(X)の実行を許可しません。

この定義はwhenにルールを設定しません。これはチェックされます。通常は例外を使用して、コンパイル時(静的な型指定)または実行時(動的な型指定)を行うことができます。両方のビットを使用できます。一部の静的型付け言語では、ある型から別の型にデータをキャストできます。また、キャストの有効性は実行時に確認する必要があります(ObjectConsumer-コンパイラーは、受け入れ可能かどうかを知る方法がありません)。

型安全性は、必ずしも強く型付けされることも意味しません-一部の言語は、型付けが弱いことで有名ですが、それでも間違いなく型安全です。たとえば、Javascriptを考えてみましょう。その型システムは、それらと同じくらい弱いですが、厳密に定義されています。データ(たとえば、文字列からint)の自動キャストを可能にしますが、ルールは明確に定義されています。私の知る限り、Javascriptプログラムが未定義の方法で動作することはありません。十分に賢い場合(私はそうではありません)、Javascriptコードを読み取るときに何が起こるかを予測できるはずです。

型安全でないプログラミング言語の例はCです。配列の境界外の配列値の読み取り/書き込みには、未定義の動作があります仕様による。何が起こるかを予測することは不可能です。 Cは型システムを持つ言語ですが、型セーフではありません。

47
Nicolas Rinaudo

ここでの多くの答えは、型安全性を静的型付けと動的型付けと混同しています。動的に型付けされた言語(Smalltalkなど)も型保証できます。

簡単な答え:操作が未定義の動作を引き起こさない場合、言語はタイプセーフと見なされます。多くの場合、言語に必要な明示的な型変換の要件はstrictly typedであると見なされます。これは、自動変換が明確に定義されていても予期しない/直感に反する動作につながる場合があるためです。

26
ididak

型の安全性は、コンパイル時の制約ではなく、実行時制約です。結局のところ、これをさらに明確にすることができると感じています。

タイプセーフティに関連する2つの主要な問題があります。メモリ**とデータ型(それに対応する操作)。

メモリ**

charは通常、文字ごとに1バイト、または8ビットを必要とします(言語に応じて、JavaおよびC#は16ビットを必要とするUnicode文字を格納します)。 intには4バイト、または32ビット(通常)が必要です。

視覚的に:

char: |-|-|-|-|-|-|-|-|

int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

型保証言語では、intをrun-timeでcharに挿入できません(これにより、何らかのクラスキャストまたはメモリ不足がスローされます)例外)。ただし、型安全でない言語では、さらに3バイトのメモリ内の既存のデータを上書きします。

int >> char:

|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|

上記の場合、右側の3バイトは上書きされるため、予測可能なchar値を取得することを期待しているそのメモリへのポインタ(たとえば3つの連続した文字)にはガベージがあります。これにより、プログラムでundefined動作が発生します(さらに悪いことに、OSがメモリを割り当てる方法に応じて他のプログラムで動作する可能性があります-最近ではほとんどありません)。

**この最初の問題は技術的にデータ型に関するものではありませんが、タイプセーフ言語は本質的に対処し、メモリ割り当てがどのように見えるかを知らない人に視覚的に説明します。

データ・タイプ

より微妙で直接的な型の問題は、2つのデータ型が同じメモリ割り当てを使用する場合です。 intとunsigned intを比較してください。どちらも32ビットです。 (char [4]とintでも簡単にできますが、より一般的な問題はuintとintです)。

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

型安全でない言語を使用すると、プログラマは32ビットの適切に割り当てられたスパンを参照できますが、unsigned intの値がintのスペースに読み込まれると(またはその逆)、再びundefinedの動作になります。銀行プログラムでこれが引き起こす問題を想像してください。

「おい!私は30ドルを貸越しましたが、今は65,506ドル残っています!」

... 'もちろん、銀行プログラムははるかに大きなデータ型を使用します。 ;) 笑!

他の人がすでに指摘しているように、次の問題は型の計算操作です。それはすでに十分にカバーされています。

速度と安全性

今日のほとんどのプログラマーは、CやC++のようなものを使用していない限り、そのようなことを心配する必要はありません。これらの言語はどちらも、コンパイラーがリスクを最小限に抑えるための最善の努力にもかかわらず、プログラマーが実行時に型の安全性に容易に違反することを可能にします(直接メモリー参照)。しかし、これはすべて悪いわけではありません。

これらの言語の計算速度が非常に速い理由の1つは、Javaなどの実行時の操作中に型の互換性を検証しても負担にならないことです。彼らは、開発者が文字列と整数を一緒に追加しない優れた合理的な存在であると想定しており、そのために開発者はスピード/効率で報われます。

25
Gr3go

「タイプセーフ」なプログラミング言語とは、次のことを意味します。

  1. 初期化されていない変数から読み取ることはできません
  2. 配列の境界を超えてインデックスを作成することはできません
  3. 未チェックの型キャストを実行できません
9
Kekule

教養学科ではなく、教養学科からの説明:

言語または言語機能がタイプセーフであると人々が言うとき、それらは、たとえば、整数を予期するロジックに整数ではない何かを渡すことを防ぐのに役立つことを意味します。

たとえば、C#では、関数を次のように定義します。

 void foo(int arg)

コンパイラは、これを行うことを私に止めさせます:

  // call foo
  foo("hello world")

他の言語では、コンパイラは私を止めることはありません(またはコンパイラがありません...)。そのため、文字列がロジックに渡され、おそらく何か悪いことが起こります。

型安全な言語は、「コンパイル時」により多くをキャッチしようとします。

欠点として、タイプセーフ言語では、 "123"のような文字列があり、intのように操作したい場合、文字列をintに変換するためのコードをさらに記述する必要があります。 123のように、「The answer is 123」のようなメッセージでそれを使用したい場合は、文字列に変換/キャストするためのコードをさらに記述する必要があります。

8
Corey Trager

理解を深めるために、タイプセーフ言語(C#)とタイプセーフ言語(javascript)ではないコードを示す以下のビデオをご覧ください。

http://www.youtube.com/watch?v=Rlw_njQhkxw

長いテキストについてです。

タイプセーフとは、タイプエラーを防ぐことです。 1つの型のデータ型が他の型にUNKNOWINGLYに割り当てられ、望ましくない結果が得られると、型エラーが発生します。

たとえば、JavaScriptは型安全な言語ではありません。以下のコードで、「num」は数値変数、「str」は文字列です。 Javascriptを使用すると、「num + str」を実行できますが、算術演算または連結を行うようになりました。

ここで、以下のコードの結果は「55」ですが、重要なポイントは、それがどのような操作を行うかによって生じる混乱です。

これは、javascriptがタイプセーフな言語ではないために発生しています。 1つのタイプのデータを他のタイプに制限なしで設定できます。

<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays  “55”
</script>

C#は型保証された言語です。 1つのデータ型を他のデータ型に割り当てることはできません。以下のコードでは、異なるデータ型で「+」演算子を使用できません。

enter image description here

4

タイプセーフとは、プログラムで、変数、戻り値、または引数のデータのタイプが特定の基準に適合する必要があることを意味します。

実際には、これは7(整数型)が "7"(文字列型の引用文字)と異なることを意味します。

PHP、Javascript、およびその他の動的スクリプト言語は通常、弱い型付けであり、「7」+ 3を追加しようとすると(文字列)「7」を(整数)7に変換します。明示的に(およびJavascriptは連結に「+」文字を使用します)。

C/C++/Javaはそれを理解しないか、結果を「73」に連結します。型の安全性は、型の要件を明示的にすることで、コード内のこれらのタイプのバグを防ぎます。

型安全性は非常に便利です。上記の "7" + 3の解決策は、cast(int) "7" + 3(10に等しい)と入力することです。

4
Jared Farrish

この説明を試してください...

TypeSafeは、コンパイル時に変数が適切に割り当てられるように静的にチェックされることを意味します。たとえば、文字列または整数を考慮します。これら2つの異なるデータ型を相互に割り当てることはできません(つまり、整数を文字列に割り当てることも、文字列を整数に割り当てることもできません)。

タイプセーフでない動作については、これを考慮してください:

object x = 89;
int y;

あなたがこれをしようとした場合:

y = x;

コンパイラは、System.Objectを整数に変換できないというエラーをスローします。それを明示的に行う必要があります。 1つの方法は次のとおりです。

y = Convert.ToInt32( x );

上記の割り当てはタイプセーフではありません。タイプセーフな割り当てとは、タイプを互いに直接割り当てることができる場所です。

ASP.NETには、タイプセーフでないコレクション(アプリケーション、セッション、ビューステートコレクションなど)がたくさんあります。これらのコレクションに関する良いニュースは、(複数のサーバー状態管理の考慮事項を最小限に抑える)3つのコレクションのいずれにもほとんどすべてのデータ型を配置できることです。悪いニュース:これらのコレクションはタイプセーフではないため、値をフェッチして戻すときに値を適切にキャストする必要があります。

例えば:

Session[ "x" ] = 34;

正常に動作します。ただし、整数値を元に戻すには、次のことが必要です。

int i = Convert.ToInt32( Session[ "x" ] );

タイプセーフなコレクションを簡単に実装するのに役立つ機能については、ジェネリックについてお読みください。

C#は型保証された言語ですが、C#4.0に関する記事に注意してください。興味深い動的な可能性が現れます(C#が基本的にOption Strict:Off ...を取得しているのは良いことです)。

2
rp.

タイプセーフは、アクセスが許可されているメモリ位置にのみアクセスするコードであり、明確に定義された許容可能な方法でのみアクセスします。タイプセーフコードは、そのオブジェクトに対して無効なオブジェクトに対して操作を実行できません。 C#およびVB.NET言語コンパイラは常にタイプセーフコードを生成し、JITコンパイル中にタイプセーフであることが検証されます。

2
Jonuz

タイプセーフとは、プログラム変数に割り当てることができる値のセットが、明確に定義されたテスト可能な基準に適合する必要があることを意味します。変数を操作するアルゴリズムは、変数が明確に定義された値のセットのうちの1つのみを取ることを信頼できるため、タイプセーフ変数はより堅牢なプログラムにつながります。この信頼を維持することで、データとプログラムの整合性と品質が保証されます。

多くの変数では、変数に割り当てられる値のセットは、プログラムの作成時に定義されます。たとえば、「色」と呼ばれる変数は、「赤」、「緑」、または「青」の値を取り、他の値を取ることはできません。他の変数の場合、これらの基準は実行時に変更される場合があります。たとえば、「color」という変数は、リレーショナルデータベースの「Colours」テーブルの「name」列の値のみを取ることができます。「red」、「green」、「blue」は3つの値です「色」テーブルの「名前」に対応していますが、コンピュータプログラムの他の部分は、プログラムの実行中にそのリストに追加できる場合があり、変数は色テーブルに追加された後に新しい値を取ることができます。

多くのタイプセーフ言語は、変数のタイプを厳密に定義し、変数に同じ「タイプ」の値を割り当てることのみを許可することにより、「タイプセーフティ」の錯覚を与えます。このアプローチにはいくつかの問題があります。たとえば、プログラムには変数「yearOfBirth」があります。これは、人が生まれた年であり、短整数として型キャストしたいという誘惑に駆られます。ただし、短整数ではありません。今年は、2009年未満で-10000を超える数値です。ただし、このセットはプログラムの実行に伴い毎年1ずつ増加します。これを「短整数」にすることは適切ではありません。この変数をタイプセーフにするために必要なのは、数値が常に-10000より大きく、次の暦年より小さいことを保証する実行時検証関数です。これらの基準は常に問題ドメインの固有の特性であるため、このような基準を適用できるコンパイラはありません。

Perl、Python、Ruby、SQLite、Luaなどの動的型付け(またはアヒル型付け、またはマニフェスト型付け)を使用する言語には、型付き変数の概念がありません。これにより、プログラマーはすべての変数のランタイム検証ルーチンを作成して、変数が正しいことを確認するか、説明されていないランタイム例外の結果に耐えることを強制します。私の経験では、C、C++、Java、C#などの静的に型付けされた言語のプログラマーは、型定義の安全性を得るために必要なのは静的に定義された型だけであると考えるようになります。これは、多くの有用なコンピュータープログラムには当てはまらず、特定のコンピュータープログラムに当てはまるかどうかを予測するのは困難です。

ロング&ショート....型安全が必要ですか?その場合は、ランタイム関数を作成して、変数に値が割り当てられたときに、明確に定義された基準に適合するようにします。欠点は、各プログラム変数の基準を明示的に定義する必要があるため、ほとんどのコンピュータープログラムでドメイン分析が非常に困難になることです。

1
Jay Godse

コンセプト:

意味のような非常に単純なタイプセーフにするために、変数のタイプが

  1. 間違ったデータ型はありません整数で文字列型の変数を保存または初期化できません
  2. 範囲外のインデックスにはアクセスできません
  3. 特定のメモリ位置のみを許可する

そのため、変数の観点からストレージのタイプの安全性についてすべてです。

1
azizsagi