2009-03-13 5 views
7

nullableでない参照型が非常に多くのバグを解決し、プログラミングを非常に簡単にする方法について人々が話し続けることを続けます。 nullの作成者であっても、彼はbillion dollar mistakeと呼ばれ、Spec#は、この問題を解決するためのnull不可能な型を導入しました。nullableでない型の議論について

編集: Spec#についてのコメントは無視してください。私はそれがどのように機能するのか誤解しました。

EDIT 2:私は間違った人と話をしなければならない、私は本当に、だから私は少数派であること、推測:-)


と主張する誰かを期待していました私は間違っているが、なぜこの議論にメリットがあるのか​​理解できない。私はバグ発見ツールとしてnullを参照しています。以下を考慮してください。

class Class { ... } 

void main() { 
    Class c = nullptr; 
    // ... ... ... code ... 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

BAM!アクセス違反。誰かがcを初期化するのを忘れていました。

class Class { ... } 

void main() { 
    Class c = new Class(); // set to new Class() by default 
    // ... ... ... code ... 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

おっと:


は今これを検討してください。ループは静かにスキップされます。問題を追跡するのに時間がかかることがあります。


クラスが空の場合、コードはとにかく失敗します。なぜあなた自身がそれを理解する必要があるのではなく、システムがあなたに(少し軽度ではあるが)言わせるのはなぜですか?

+0

他の人がヌルを楽しむのはうれしいです、私はまだ学校にいるので、私には何かがないと仮定しています。 –

+1

"無価値"を扱うもっと原理的な方法があります。 NULLは、intなどのプリミティブ型を除外します。型システムでは、暗黙的に参照するのではなく、すべての型で一貫して値の不足を表現する方が優れています。 Haskellの "Maybe"とML/OCaml/F#の "option"型を見て、それをどうやってやるべきかを見てください。 – MichaelGG

+0

[nullのない言語のベスト解説]の複製が可能です(http://stackoverflow.com/questions/3989264/best-explanation-for-languages-without-null) – nawfal

答えて

-2

私はNULLの使用が好きです。私はC++で作業して以来、しばらくしていましたが、戻り値や参照に関する問題を見つけて修正するのが非常に簡単でした。

+0

ポイントが見つかりません。 –

2

私はSpec#について多くのことを本当に読んでいないことを認めますが、NonNullableは本質的に、変数宣言に必須ではないパラメータに付けた属性であることを理解していました。あなたの例を次のように変えてください:

class Class { ... } 

void DoSomething(Class c) 
{ 
    if (c == null) return; 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

void main() { 
    Class c = nullptr; 
    // ... ... ... code ... 
    DoSomething(c); 
} 

Spec#では、「パラメータcはnullにはできません」とマーキングしています。 DoSomething()メソッドの最初の行(DoSomething()のコンテキストには完全に無意味な行を忘れやすい)を必要としないので、これは私には良い機能のようです。

6

私はあなたの例を理解していません。あなたの "= new Class()"がヌルを持たない代わりにプレースホルダであるならば、それは明らかにバグです。そうでない場合、実際のバグは、「...」が内容を正しく設定しなかったことです。どちらの場合もまったく同じです。

cを初期化するのを忘れてしまったことを示す例外は、初期化されていない点と初期化されていない点を教えてくれます。同様に、欠落したループは、(暗黙のうちに)0以外の.countを持つ必要がある場所を教えてくれます。私はいずれかがプログラマにとってもっと簡単であるとは思わない。

「ヌルなし」のポイントは、テキスト検索と置換を行い、すべてを空のインスタンスにすることだとは思わない。それは明らかに役に立たない。重要なのは、コードが構造化され、変数が無用/間違った値を指している状態にならないようにすることです。そのうちのNULLが単なる最も一般的なものです。

+0

したがって、言語がnull以外の型を実装している場合、 "Class c;" cを?に設定します。 (私はまったくあなたのコメントに同意します) – zildjohn01

+2

私の最初の考え:それは許されるべきではありません。論理的には、「Fooを格納しなければならないスロットを作る(空のままにする)」と言っても意味がありません。これはおそらくLispやRubyのようなすべての表現を必要とするでしょう - 割り当てを行うために逐次ステートメントを実行しなければならない場合、どうすればうまくいくのか分かりません。 – Ken

+1

振り返る:SQLを考える。 「NOT NULL」列があり、それにnull以外の値を指定せずにレコードを挿入しようとすると、単にエラーが発生します。 – Ken

0

私には、nullが使用される2つの領域があります。

最初は値がないことです。たとえば、ブール値はtrueまたはfalse、またはユーザーがまだ設定を選択していないためnullです。これは便利で良いことですが、おそらく最初は正しく実装されておらず、その使用を正式化しようとしています。 (set/unset状態を保持する第2のブール値が存在するか、3状態論理の一部としてヌルが存在するか)

2番目の値はNULLポインタの意味です。これは、プログラムエラーの状況よりも頻繁に発生します。例外。これは意図した状態ではないため、プログラムエラーがあります。これは現代の言語で実装されている正式な例外の傘の下にあるべきです。つまり、try/catchブロックを介してNullExceptionがキャッチされます。

これらのうちどれに興味がありますか?

+0

#2。 – zildjohn01

2

null以外の型の考えは、クライアントではなくコンパイラがバグを見つけられるようにすることです。 @nullable(nullの場合もあります)と@nonnull(nullでない場合)の2つの型指定子を言語に追加するとします(Javaアノテーション構文を使用しています)。

関数を定義するときに、その引数に注釈を付けます。たとえば、次のコードでは、fooがエントリー、あなたがfoo.size()を呼び出すときに、fooがNULLでない、という制御保証のフローでヌルであっても

int f(@nullable Foo foo) { 
    if (foo == null) 
    return 0; 
    return foo.size(); 
}

をコンパイルします。

ただし、nullのチェックを削除すると、コンパイル時エラーが発生します。

fooがエントリでNULLでないので、次のことがあまりにもコンパイルします:

int g(@nonnull Foo foo) { 
    return foo.size(); // OK 
}

しかし、あなたがNULL可能ポインタでグラムを呼び出すことができなくなります。

@nullable Foo foo; 
g(foo); // compiler error!

コンパイラはありません@nullableが@nonnullになったときに検出することができます(たとえば、nullをチェックするif文の内部)。また、即座に初期化されていれば、@nonnullの検証可能な定義を受け入れます。

@nonnull Foo foo = new Foo();

さらに詳しい情報はmy blogです。

0

現在、このトピックはC#で作業しています。 .NETには値型のNullableがありますが、参照型の逆関数は存在しません。

参照型にNotNullableを作成し、その問題をデータ型ドメインに移しました。これにより、アプリケーションはコンパイル時ではなく実行時に例外をスローします。

12

応答は、このスレッドで「答え」をマークしていること少し奇妙ITSは実際には、すなわち、最初の場所でヌルに問題があることを浮き彫りに:

私はNULLのほとんどは ポインタエラーことも発見しました 関数を忘れて、 string.hの関数が返されたことを確認してください。 ここで、NULLが指標として使用されています。

実行時ではなく、コンパイル時にコンパイラがこれらの種類のエラーをキャッチできるかどうかは気になりませんか?

MLのような言語(SML、OCaml、SML、F#など)をHaskellまたはHaskellで使用している場合、参照型はnullを使用できません。代わりに、オプション型をラップすることによって "null"値を表します。このようにして、ヌルを正当な値として返すことができる場合は、関数の戻り値の型を実際に変更します。それでは、私はデータベースからユーザーを引っ張ってみたかったとしましょう:

let findUser username = 
    let recordset = executeQuery("select * from users where username = @username") 
    if recordset.getCount() > 0 then 
     let user = initUser(recordset) 
     Some(user) 
    else 
     None 

検索ユーザーがタイプval findUser : string -> user optionを持っているので、関数の戻り値の型は、実際にはnull値を返すことができることを示しています。コードを消費するには、両方の一部となしのケースを処理する必要があります:あなたは両方のケースを処理していない場合は、コードもコンパイルされません

match findUser "Juliet Thunderwitch" with 
| Some x -> print_endline "Juliet exists in database" 
| None -> print_endline "Juliet not in database" 

。したがって、型システムは、null参照例外を絶対に受け取らないことを保証し、常にnullを処理することを保証します。また、関数がuserを返した場合、それはオブジェクトの実際のインスタンスであることが保証されます。感謝します。

今、私たちはOPのサンプルコードで問題を参照してください。

class Class { ... } 

void main() { 
    Class c = new Class(); // set to new Class() by default 
    // ... ... ... code ... 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

初期化され、初期化されていないオブジェクトは、同じデータ型を持っている、あなたはそれらの間の違いを見分けることはできません。場合によってはnull object patternが役に立ちますが、上記のコードでは、コンパイラが型を正しく使用しているかどうかを判断する方法がないことを示しています。

0

ドメインオブジェクトを扱っているときに、ヌル入力不可能な型は私にとって意味があります。データベーステーブルをオブジェクトにマッピングしていて、null値を許可しない列がある場合。ユーザーと呼ばれるテーブルがあり、カラムuserid varchar(20)がヌル可能ではないとします。

これは、null可能でないUserId文字列フィールドを持つUserクラスを持つと便利です。コンパイル時にいくつかのバグを減らすことができます。

関連する問題