変数に型が必要なのはなぜですか?


10

だから私たちは書きます:

Customer c = new Customer();

なぜ私たちが書いたようなデザインではないのですか?

c = new Customer();
c.CreditLimit = 1000;

コンパイラーは、顧客を指すcポイントを計算し、顧客のメンバーをcで呼び出すことを許可できますか?

私たちは書きたいと思うかもしれません:

IPerson c = new Customer();
IPerson e = new Employee();

書くことができるように:

public string GetName(IPerson object)
{
    return object.Name
}

string name = GetName(c); // or GetName(e);

しかし、私たちが書いた場合:

c = new Customer();
e = new Employee();

私たちはまだ書くことができます:

public string GetName(object)
{
    return object.Name
}    

string name = GetName(c); // or GetName(e);

オブジェクトのc参照のタイプがNameプロパティをサポートしていない場合(メソッド内の引数/パラメーターで使用されているメンバーを確認できるため)、コンパイラーはすぐ上のコードについて文句を言うか、ランタイムが文句を言う可能性があります。

C#の動的キーワードを使用しても、変数「タイプ」を使用しています(実行時に決定されます)。しかし、なぜ変数に型が必要なのでしょうか。確かに理由はあるに違いないが、考えられない!


12
これが、PythonやRubyなどの動的言語がある理由です。この質問に対する答えはありません。型宣言を使用する言語と使用しない言語があるのは事実です。
S.Lott、2012

2
「これらの言語の変数には型がまったくありませんか?」正しい。 Pythonでは、変数には型がありません。オブジェクトにはタイプがあり、変数は単にオブジェクトへの参照です。あなたの質問は実際には単なる観察です。具体的には、「すべての言語で変数宣言が必要なわけではありません」。答えはありません。そのため、建設的ではないため閉鎖される可能性があります。
S.Lott、2012

1
あなたは見てとることもできますブーあなたが任意の型宣言せずに変数を宣言することができますが、使用して、型推論を使用すると、強い型付けの正確性およびパフォーマンスの利点を犠牲にしないようなタイプを把握するの。
メイソンウィーラー、

2
var x = 1; -32ビット、64ビット、16ビットの数値ですか?バイト?浮く?ダブル?小数?これはプリミティブを扱っているだけです。
ジョブ

4
varC#で使用でき、変数を宣言する場所を明示することは常に適切です。
ダニエルリトル

回答:


22

しかし、なぜ変数に型が必要なのでしょうか。

  1. これは、無効で誤って入力された式が変数に割り当てられているバグをキャッチする場合があります。一部の言語には動的型付けがあります。これにより、変数ごとの型の正確性の保証が、望まれるような柔軟性のために犠牲になります。
  2. 型により、コンパイラはより効率的なコードを生成できます。動的型付けとは、実行時に型チェックを実行する必要があることを意味します。

1
反対票について説明してください。
Fred Foo、

4
また、実行時に型情報を確認する必要があるため、動的型付けにはパフォーマンスコストがかかります。
Charles Salvia、2012

@CharlesSalvia:良い点、それを答えに加えた。
フレッドフー

2
@sturdytree:「型がない場合は、誤って型付けすることはできません」-言語規則に関する限り、それは事実です。ただし、セマンティックの観点からは、変数に間違った型が割り当てられている可能性があります。たとえば、コンストラクター名を誤って入力してもプログラムは実行されますが、期待どおりに動作しません。
Fred Foo

5
@sturdytree 型チェックを使用して本当に型なしの変数を持つ言語がないことは事実ですが、型推論を持つ言語があります。つまり、言語は変数の使用方法を調べ、使用方法から型を推定します。競合がある場合(たとえばa = new Bar()、クラスからメソッドを実行して後で呼び出す場合Baz)、コンパイラーはエラーを発生させます。HaskellやOCamlのような言語は型推論のパイオニアですが、C#にはvarキーワードとともに存在します。
クォンクル

9

完全に有効なポイントがあります。変数の型を追跡しない言語が存在し、「動的型付け」と呼ばれます。このカテゴリには、JavaScript、Perl、Lisp、Pythonなどの言語が含まれます。

静的に型付けされた言語から得られる利点は、追加のコンパイル時エラーチェックです。

たとえば、次のメソッドがあるとします。

public addCustomerContact(Customer client, Employee contact) {
   ...
} 

コードに顧客bobと従業員jamesがいる場合、誤ってを呼び出す可能性がありますがaddCustomerContact(james, bob)、これは無効です。しかし、コンパイラーが変数のタイプを認識していない場合、無効な呼び出しを行ったことを警告することはできません。代わりに、実行時にエラーが発生します...そして動的に型付けされた言語は、メソッドに渡されるパラメーターのタイプ。この問題は、コードがjamesオブジェクトの顧客のみのプロパティ、またはオブジェクトの従業員のみのプロパティを使用しようとするたびに発生しbobます。これは、ペア(james、bob)が顧客の連絡先のリストに追加されてからかなり後になる可能性があります。

さて、疑問に思うかもしれませんが、なぜコンパイラはjamesand の型を推測できず、bob警告を出すことができないのでしょうか。それが可能な場合もありますが、変数に実際に型がない場合は、次のようにすることができます。

var james;
var bob;
if (getRandomNumber() > 0.5) {
   james = new Customer();
   bob = new Employee();
} else {
   james = new Employee();
   bob = new Customer();
}

変数には型がないため、変数に値を割り当てることは完全に合法です。これは、変数のタイプを常に知ることができるとは限らないことも意味します。それは、実行の異なるパスに基づいて異なるタイプになる可能性があるためです。

一般に、動的に型付けされた言語は、コンパイル手順がないスクリプト言語に使用されるため、コンパイルエラーは発生しません。つまり、変数に型を指定するために必要な追加のキーストロークはあまり役に立ちません。

動的に型付けされた言語にもいくつかの明確な利点があります。ほとんどが同じデザインを実装するために必要なコードが少ないという点でです。すべてが「ダック型」であるため、インターフェイスを記述する必要はありません(オブジェクトにどのメソッド/プロパティがあるかだけを気にします) 、オブジェクトが属しているクラスではありません)、変数に明示的なタイプを指定する必要はありません...コードの実行を開始する前に、バグがいくらか少なくなるというトレードオフがあります。


セオドアに感謝します。「しかし、コンパイラーが変数のタイプを知らなくても、無効な呼び出しを行ったことを警告することはできません。」コンパイラーは、変数が指すオブジェクトのタイプを知ることができます。
rigidtree

セオドア:あなたの例のjames / bobでは、プログラマーが変数をどのように使用したか(そして適切な名前付けが役立つか)を知っている必要があるので、問題はありません。「変数の型を常に知ることはできない」と言ったとき、変数が指すオブジェクトの型を常に知ることはできないと思いますが、コンパイラーはこれを解決して、正しくないメンバーが存在することを警告できます。適用されます(つまり、静的チェックを行うことができます)。
rigidtree

2
上記の例では、オブジェクトのタイプを静的に知ることができません。実行パスによっては、タイプ情報のない変数に格納されているオブジェクトのタイプが異なる場合があります。コンパイル時の型情報を推測できるC#のような言語を使用できますが、私が知る限り、静的型チェックと真に型なしの変数の両方を備えた言語はなく、静的分析の計算の複雑さもおそらくありますすごい。
セオドアマードック

セオドア、ありがとうございます。私が話しているのは、静的型チェック(オブジェクトの型に基づく)と型なし変数を備えた言語であることを正しく理解しました。Pythonには型のない変数があると聞いていますが、静的な型チェックがないようです。
rigidtree

1
-1; 強い/弱い型付けは、静的/動的な型付けと直交しています。Cは静的に弱く型付けされています。LispとPythonはどちらも動的に強く型付けされています。
Fred Foo

5

したがって、プロのプログラマーは、

10 + "10"

is "1010" or 20....

静的に型付けされた言語でのコンパイル時、または動的に型付けされた言語での実行時のエラーとは何か。とにかく正気なもの。


2
つまり、Perlはまともな言語ではありませんか?:)
フレッド・フー

5
@larsmans:実際のところ、違います。違います。しかしそれは純粋に意見です。
NotMe

2
@ChrisLively:それが今の問題でよかった。Perlを愛する同僚を納得させるために、いつでも私の職場に来てください;)
Fred Foo

2
10 + "10"は、整数型のオブジェクトと文字列型のオブジェクトで「+」演算子を使用しています。コンパイラーはエラーを出します。私の質問は、オブジェクトではなく、変数のタイプに関係しています。
rigidtree

2
これは、ある有効なC:それのポインタ演算。
dan04

4

変数one(1に設定)があり、を評価しようとしたとしone + oneます。タイプがわからない場合は、1 + 1があいまいになります。2または11が正解である可能性があると主張できます。コンテキストが与えられないとあいまいになります。

私は、これはデータベースの種類が不注意に設定されたSQLiteの中で起こる見てきたVARCHARのではなく、INTかつ操作が行われたとき、人々は予期しない結果を得るました。

C#では、コンテキストが型を推論する場合、varキーワードを使用できます。

var c = new Customer();
var e = new Employer();

コンパイル時に推論された型でcおよびeをコンパイルします。


1
Pythonでは、1 + 1常にtypeを持ってintいますが、それを宣言する必要はありません。問題は、変数にではなく型がある理由です
Fred Foo

申し訳ありませんが、私が私の例で使用したときは表示されvariablesませんでしvalues1 + 1。はっきりしていないと思います。
Stephen Quan

それでも、動的に型付けされた言語はこれに対処できます。Pythonでは、をone=1; print(one+one)出力し2ます。one="1"; print(one+one)プリント11。SQLiteの例はより説得力がありますが、弱い型付けの問題があるため、C#にはあまり関係がありません。
Fred Foo

私が提案したスキームでは、1 = 1は整数型を指す変数を意味します(型をまったく提案していません-オブジェクトには型があります)。1つ+ 1つがあいまいになることはありません(2つの整数オブジェクト/値を追加しています)
rigidtree

1
こんにちは@ dan04、私はフィールドでORDER BYうっかりやってしまいましたVARCHARstackoverflow.com/questions/9103313/…を参照してください。
スティーブンクアン

4

変数は、関連する型を持つ必要はありません。これが当てはまる言語には、Lisp、Scheme、Erlang、Prolog、Smalltalk、Perl、Python、Rubyなどがあります。

変数型を持つことも可能ですが、プログラムで型を記述する必要がない場合もあります。これは通常、型推論と呼ばれます。ML、Haskell、およびそれらの子孫には強力な型推論があります。他の一部の言語では、C ++のauto宣言など、それをより小さな形式で使用しています。

型推論に対する主な議論は、それが読みやすさを損なうということです。タイプを書き留めておくと、通常はコードを理解しやすくなります。


1

変数が表す型を特定するときは、いくつかのことについて説明します。変数のメモリ割り当て要件を特定し、変数の互換性と範囲のルールを定義しています。これは、格納するデータの意図についての混乱を回避し、コンパイル時にコードの潜在的な問題を特定する比較的安価な手段を提供する方法を提供します。

次の変数を宣言すると、

myVar      = 5;
myOtherVar = "C";

これらの変数について何を推測できますか?されたmyVar符号付きまたは符号なし?8ビット、64ビット、またはその中間の何かですか?あるmyOtherVar文字列(効果的に配列)またはchar?それはANSIまたはUnicodeですか?

特定のデータ型を指定することで、アプリケーションのメモリ要件を最適化する方法についての手がかりをコンパイラに提供します。一部の言語ではこのようなことをあまり気にせず、実行時にそれらの問題を処理できますが、他の言語ではコードを分析することでデータ型を推測できるため、ある程度の動的型付けが可能になります。

強く型付けされた言語のもう1つのポイントは、変数を使用するたびにコンパイラーに命令を提供する必要がなくなることです。変数にアクセスするたびに、その変数を効果的にキャストしてコンパイラーに値のタイプを伝えるよう強制された場合、コードがどれほど恐ろしくて読みにくくなるか想像できますか?


良い点、コンパイラーは値に基づいて最も効率的なタイプ(たとえば、小さなint)を使用することができますが、特定の操作を実行できるように、「C」をcharではなく文字列オブジェクトにしたい場合があることがわかります。 。そのような場合でも、=(文字列) "C"を指定するだけで済みます。これは文字列オブジェクトを作成し、 'a'(型なし変数)はそれを指し示すだけです。これは文字列a = "C"よりも恐ろしいとは思わない。
rigidtree

0

コンピュータープログラムは、プロセスノードのグラフであり、言語ランタイム(ほとんどの場合、ツールキットで拡張された)で表される「マシン」が、どのような順序で、どのような条件で実行するかを記述します。このグラフは、特定の言語で記述されたテキストファイル(または一連のテキストファイル)で表され、コンパイラー/インタープリターがこのファイルを読み取る(逆シリアル化する)ときに(部分的または完全に)作成されます。また、このグラフを実際に作成し、ターゲット言語でソースコードを生成できる環境(UMLまたはグラフィカルプログラム生成ツール)もあります。

なぜこれを言うのですか?これがあなたの質問への答えにつながるからです。

プログラムテキストは、コンピューターが実際のタスクをどのように解決するかについての指示であり、プロセスステップ(条件、アクション)と構造(ソリューションで使用するコンポーネント)の両方を含みます。後者は、他のコンポーネントのインスタンスを取得または作成し、それらを名前付きボックス(変数)に入れて使用することを意味します。それらのデータとサービスにアクセスします。

一部の言語では、ラベルだけが重要ですが、何でも入れることができる均一なボックスを提供します。「target」という名前の変数を使用して、最初に「Person」、最後に「Car」を格納することもできます同じアルゴリズム。他の人は「形の」ボックスを作成する必要があるため、「ジェネリックボックス」(Javaオブジェクト、C / C ++ void *、Objective C "id" ...)を作成することはできますが、人または車には異なるボックスが必要です。好きなようにキャストしてください。型付き言語を使用すると、構造をより詳細に表現し、変数の「型コントラクト」を作成できます(ただし、この制限を回避できます)。型なし言語は、この「このボックスに何を入れたかを確実に知る」アプローチをサポートしています。デフォルトで唯一の動作です。

どちらのアプローチも実行可能であり、コンパイラインテリジェンス、さまざまなレベルでそれらを使用して記述された多くのプログラミングブック、プラクティス、およびフレームワーク(およびそれらのフレームワークに関する他の大量のブック)があります。したがって、今日の答えは、型を使用するかどうかについての適切に作成、測定、検証されたステートメントよりも、実際のプログラマチームの好みと知識の問題のようです。

トリックよりも、特に長期の大きなチーム(別名:深刻な)プロジェクトの場合は、ルールを好むことは言うまでもありません。理由:私が知っている限り、SWプロジェクトの失敗/スリップの最も可能性の高い原因は、不明確な要件と設計の不備(80%!私が知っている調査による)であり、実際のコーディングには数パーセントしか残っていません。すべてのルールと契約は、前向きに考えてよりクリーンな設計を実施し、適切な人々が早期に決定を下す必要があります。タイプはルールを意味します。「自由度」と「クールさ」の低下-準備、思考、コーディング標準、チームワークの制御。私にとって、これは成功の必須の要素のように聞こえ、「家、甘い家」でもあります。

私の2セント。


-3

AFIAK動的型付けのすべての言語は解釈言語です。これはすでに非常に非効率的です。動的型付けの非効率性を追加しても、時間の大きな損失にはなりません。ただし、コンパイルされた言語は、実行時に実際に名前で参照しているわけではありません。(.netリフレクションなどの時折の使用を禁止する-基礎となる言語と比較して非常に遅い機能。)これらすべての名前の検索は遅く、遅く、遅くなります。


3
あなたは間違っています。動的に型付けされた言語には多くのコンパイラがあり、それらのいくつかは非常に高速です。例としては、Common Lisp、Scheme、Erlangなどがあります。
ライアンカルペッパー

3
「解釈された言語」のようなものはありません。言語は、数学的なルールの抽象的なセットです。言語はコンパイルも解釈もされません。言語はただです。コンパイルと解釈は、言語ではなく実装の特性です。すべての言語はインタープリターで実装でき、すべての言語はコンパイラーで実装できます。そして、ほとんどすべての言語がインタープリターとコンパイルされた実装の両方を持っています。たとえば、CのインタープリターとECMAScript、Ruby、Pythonのコンパイラーがあります。
イェルクWミッターク

-4

動的に型付けされた言語は、しばしば「オブジェクト指向」として宣伝されています。ではない。それらはカプセル化指向であるかもしれませんが、決してオブジェクト指向ではありません。オブジェクト指向はすべてタイプに関するものです。

「少年は兄の自転車に乗って食料品店に行き、食料品店からパンを買います。」オブジェクト指向を使用すると、クラス(タイプ)のセットをすぐに記述して、この現実のシナリオを記述することができます。

動的に型付けされた言語では、シナリオは次のようにしか表現できません。

「オブジェクトはオブジェクトのオブジェクトに乗ってオブジェクトからオブジェクトを購入します」。

オブジェクト指向の力は、世界を自然な形でモデル化する能力にあります。これにより、ソフトウェア開発者は脳の両側を使用してソフトウェアを記述し、コンピュータープログラマーではなく人間としてより多くの問題を解決できます。この能力は、動的に型付けされた言語にはありません。

静的型付けにより、統合開発環境は変数のタイプを認識できるため、コーディング効率、再利用性、保守性が向上します。変数のタイプを知っているIDEは自動補完を提供できるので、プログラマーは、メンバープロパティのスペルが「backlightControl」、「backLightControl」、「bkLightCtrl」のいずれであるかを覚えるために、クラス定義を参照する必要がありません。

IDEは、変数がリファクタリングされているオブジェクトのインスタンスを保持するすべての場所を知っているため、静的型付けにより自動リファクタリングが可能になります。

静的型付けにより、再利用性と保守性が向上します。動的型付けは、使い捨てコードに適しています。新しい開発者が通りからやって来て、既存のコードを見てみます。コードが静的に型付けされている場合、開発者は2回のマウスクリックで、関連する各変数のクラス定義を調べ、クラスの目的を理解し、利用可能な他のメソッドとプロパティを知ることができます。コードが動的に型付けされている場合、開発者はグローバル検索を使用して何が起こっているのかを理解する必要があります。


2
私はあなたの議論の最初の部分であなたに同意しなければならないと思います。動的型付け言語は通常「オブジェクト指向」ですが、「クラス指向」ではありません。これは重要な違いです。あなたの例では、あなたは実際に幻想の中に住んでいます。あなたはBoyクラスを持っているかもしれませんが、私はそれが現実の「少年」がするすべてのことをすることができるとは思えません。ただし、動的な例(オブジェクトが乗る...)では、この「少年」オブジェクトの唯一の重要なこと、つまり乗ることができることがわかります。それが動的型言語の基本的な考え方です。+ ve sと-ve sがあります。あなたが好きなのはあなたの意見です。
チップ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.