2010-12-17 61 views
27

在F#中有一個很重要的地方,它們沒有空值,也不想支持它。仍然程序員不得不提供類似於C#程序員必須檢查!= null的情況。沒有比null更邪惡嗎?

是不是真的比null更邪惡?

+6

這可能是一本關於禪的稱號! – TechNeilogy 2010-12-17 14:45:57

+2

當然比'type bool = True |更好False | FileNotFound' – Juliet 2010-12-17 16:53:51

+0

另請參見http://stackoverflow.com/questions/3989264/best-explanation-for-languages-without-null – Brian 2010-12-18 03:12:11

回答

30

當然它不那麼邪惡!

如果不針對None進行檢查,那麼大多數情況下,應用程序中會出現類型錯誤,這意味着它不會編譯,因此它不會因NullReferenceException而崩潰(因爲None轉換爲null) 。

例如:

let myObject : option<_> = getObjectToUse() // you get a Some<'T>, added explicit typing for clarity 
match myObject with 
| Some o -> o.DoSomething() 
| None -> ... // you have to explicitly handle this case 

但仍可以實現類似C#的行爲,但它是不太直觀,因爲你必須明確地說:「忽略,這可能是無」:

let o = myObject.Value // throws NullReferenceException if myObject = None 

在C#中,您不必強制將變量的情況視爲null,因此您可能只是忘記進行檢查。同上例如:

var myObject = GetObjectToUse(); // you get back a nullable type 
myObject.DoSomething() // no type error, but a runtime error 

編輯:斯蒂芬·斯文森是絕對正確的,我的例子代碼有一些缺陷,在匆忙中寫它。固定。謝謝!

+0

即使在C#中,如果不檢查空值,您將在ReSharper中收到警告 – JoelFan 2010-12-17 11:27:36

+1

@Carlo V. Dango,@SplashHit在使用選項類型時,您有非常方便的方法Option.Map和Option.bind,加上它會強制您處理無和理由。你也可以以安全的方式輕鬆擴展你的代碼,以防你想要比二進制Some(somthing)或None(nothing)更多的結果。 – jlezard 2010-12-17 11:48:57

+0

@SplashHit:使用C#,您需要額外的(外部)幫助來管理空檢查。使用F#,Option類型使這部分語言成爲可能。 – pblasucci 2010-12-17 13:16:38

34

null的問題是,你必須使用它幾乎無處不在,即引進無效狀態,其中這是既不打算也不有道理的可能性。

有一個'a option總是一個明確的事情。您聲明操作可以生成有意義的值SomeNone,編譯器可以執行強制執行以進行正確檢查和處理。

通過阻止null轉而支持'a option類型,您基本上可以保證程序中的任何值都具有某種意義。如果某些代碼設計爲使用這些值,則不能簡單地傳遞無效代碼,並且如果存在option類型的函數,則將有具有以涵蓋所有可能性。

+2

這個答案是遠遠優於接受的一個伊莫(雖然都很好)。 ShdNx的回答涉及爲什麼選項很好,但是這個實際上將它與null比較,並回答它真的不那麼邪惡(甚至是太棒了!)。希望我能夠第二次投票;謝謝你達里奧! – MasterMastic 2014-01-28 17:44:40

14

比方說,我告訴你一個函數的定義是這樣的:

val getPersonByName : (name : string) -> Person 

你覺得當你在誰不會在數據存儲存在的人的name傳會發生什麼?

  • 該函數是否會拋出NotFound異常?
  • 它是否返回null?
  • 如果他們不存在,它會創建人嗎?

閱讀代碼(如果您有權訪問它),閱讀文檔(如果有人足夠寫它)或者只是調用函數,您無法知道。這基本上是空值的問題:它們的外觀和行爲與非空值相同,至少在運行時纔會發生。

現在讓我們假設你有一個函數與此簽名改爲:

val getPersonByName : (name : string) -> option<Person> 

這個定義可以很明確的會發生什麼情況:你要麼得到一個人回來,或者你不會和這種信息在函數的數據類型中傳遞。 通常,您可以更好地保證處理選項類型的兩種情況而不是可能的空值。

我會說選項類型比nulls更仁慈。

+1

在f#中,也可以在給定這樣的函數聲明時拋出異常 – 2010-12-22 09:05:21

3

In F# its a big deal that they do not have null values and do not want to support it. Still the programmer has to make cases for None similar to C# programmers having to check != null.

Is None really less evil than null?

null介紹了運行時錯誤(NullRefereceException)每取消引用在C#中,None力量的對象,你使運行時錯誤在F#明確的來源時的潛在來源。

例如,一個給定的對象上調用GetHashCode導致C#到靜默注入運行時錯誤的來源:

class Foo { 
    int m; 
    Foo(int n) { m=n; } 
    int Hash() { return m; } 
    static int hash(Foo o) { return o.Hash(); } 
}; 

相反,在F#的等效代碼預計將null自由:

type Foo = 
    { m: int } 
    member foo.Hash() = foo.m 

let hash (o: Foo) = o.Hash() 

如果你真的想在F#中的可選值,那麼你可以使用option類型,你必須明確地處理它,否則編譯器會給出警告或錯誤:

let maybeHash (o: Foo option) = 
    match o with 
    | None -> 0 
    | Some o -> o.Hash() 

您仍然可以通過規避類型系統(這是需要互操作)獲得F#NullReferenceException

> hash (box null |> unbox);; 
System.NullReferenceException: Object reference not set to an instance of an object. 
    at Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.UnboxGeneric[T](Object source) 
    at <StartupCode$FSI_0021>[email protected]() 
Stopped due to error