LemonHX

LemonHX

CEO of Limit-LAB 喜欢鼓捣底层的代码,意图改变世界
twitter
tg_channel

討論程式語言的易用性與強型別和弱型別

sjb.png

歡迎任何困惑網上論戰 strong type 和 weak type 語言是什麼東西的萌新以及正在學習類型理論的人前來觀看~

我只想說網路上大部分關於這部分的爭吵都是錯的!而且出錯的方向都太離譜了。

首先非常感謝客座作者 dannypsnl 大家可以看他的部落格!#

Type 本質上是什麼東西#

Weak Type 與 Strong Type#

事實上你不能描述一個語言是不是 strong type 還是 weak type,因為 strong 和 weak 每個人都有一個內心的區間,當然對於大多數普通開發者而言這個區間範圍都是錯誤的。

甚至對於專業的理論學者而言他們內心裡的區間也是錯誤的,我們經過了一晚上的討論終於大致把這個去加縮小到了下面五個範圍,現在無論是學術界還是民科都無法用穩定的名詞去描繪區間,我們只好嘗試描述並舉例。

第一梯隊:執行時型別完整符合編譯時型別且全部靜態不可變更且理論完備#

這一梯隊的語言基本不存在,因為這個區間能夠保證整個語言運行在靜態且可預測的狀態,先不說停機問題,這種模型就限制了語言與外界的交互。

我們可以簡單科普一下歷史,在遙遠的 20 世紀,曾經有一個語言叫 Miranda (Haskell 的爹),那個時候基本每個大學都有一個這個語言的 fork... 因為 Miranda 基本無法編寫日常的程式,大家只好在上面糊一層又一層的 DSL 打各種各樣的洞才能跑各種實際上有 **"意義"** 的程式。

這裡的有意義的程式指的不是拿來發 PL paper 的也不是各種 type safe calculator。

基本不存在 Miranda 根本寫不了任何跟本機交互的程式... 這是歷史前提。

然後他們這一群大學進行了一次茶話會,最終創造出來並沒有那麼嚴謹的 Haskell。

(上面的歷史有省略一部分內容,但大體上是這樣的)

為什麼他們自降等級到第二梯隊?因為第一梯隊的實際價值並不夠普世,寫不出程式的程式語言有什麼誕生的必要呢?

所以我們總結一下:對於第一梯隊的語言使用者可以完全相信程式碼但寫不出來任何有意義的程式。

第二梯隊:執行時型別完整符合編譯時型別且全部靜態不可變更且理論完備的基礎上允許 Casting#

  • Haskell
  • Rust
  • C

只要我們允許了一部分 Casting 和打洞,我們就可以實際上的和現有的帶有非常複雜的副作用的世界進行溝通了!通常在這一梯隊的語言因為他們相對上理論更加的完備,從而能讓完美了解他背後的理論的程式設計師可以無腦寫程式。

(注意加粗字體)

但是往往他們的理論 (對於正常的本科學歷且沒有 PL 相關的知識的程式設計師) 非常的複雜如 Haskell 的 $System\ F_\omega$

但是這不代表說對於專業的程式設計師來說這個就是壞事兒,但是總有那麼一些 case 會不得不繞大圈子,俗稱做型別體操

我們可以總結一下在這個梯隊的語言是需要一定專業的知識就可以無腦寫出安全的程式碼,對於這一梯隊的語言往往評價非常的兩極分化。

最近火起來的 Rust 語言大體上也在這個位置。

其實 C 語言也在這個位置,但是關於 C 我們一會兒再說。

第三梯隊:有編譯時型別且執行時動態不可變型別且有檢查#

在這一梯隊我們就可以看到非常最近流行的一些腳本語言了。

  • elixir
  • ruby3
  • typed-racket
  • typescript*(我們給他臉放到這個位置,否則我們還會再多一個叫有編譯期不可靠型別同時與執行時行為無關的梯隊)

這一梯隊平時除了 ts 大家接觸的可能都不是很多,其實就是本質上我們能夠保證大部分 (上面的梯隊是只要好好寫程式基本所有) 程式都符合編譯期間的型別檢查,同時預留了諸如 any 這種東西來保證作為腳本語言的動態性。

這一梯隊的書寫體驗效果極佳,除非是專業人員過來,否則評價都清一色的一邊倒的說好。

總結一下,這一梯隊的主要特點呢是使用者不會遇到任何不符合作者期望的執行時錯誤,且使用者可以在程式碼執行前相信大部分程式碼。

第四梯隊:無編譯時型別有執行時動態不可變型別且有檢查#

這一部分語言就是我們平常人開始分不清是弱型別還是執行時強型別 (動態型別) 的語言了,比如說這個區間裡包含幾個代表語言。

  • JS* (這個沒有在第五梯隊,因為本質上來講其實 JS 還是可以自圓其說的)

  • Erlang

  • Ruby2

這一類語言屬於作者水平有限或者根本寫的時候就沒想過要流行或者當時技術限制導致的產物,特點主要是使用者會遇到不符合期望的執行時錯誤,使用者只可以相信說明文件(前提是他有好好寫) 完全不可以相信程式碼。

Type 的階級會隨著你看待這個語言的角度發生變化#

到這裡有人其實會詫異為什麼 C 語言會在第二梯隊呢?

怎麼引發了無數的 Bug 的 C 語言能跟 Haskell 站在一起?

其實,C 語言人家在造的時候就沒有考慮到你可能會引發這種內存不安全的問題,所以這個問題本來就不在 C 要解決的問題的範疇之內,其次假如你當 C 語言是一個 nominal (就是名稱型別) 型別的語言,他會落在第五梯隊,但是假如你真的了解作者所期望的用途,你看待他的 type 是 size (也就是我們俗稱的C ABI) 他就能夠能達到第二梯隊的嚴謹性,這就是為什麼有的 C 程式設計師說 C 是一個非常嚴謹的語言但大部分人並不這麼認為。

因為大部分人都對數字不敏感,這可能是我們的基因導致的 (

另外一個可能的路線: Structural Typing#

但是沒有任何語言的成熟的實現,但是這一套東西確實能在第二階描述出第四階的行為。

語言的易用性和 Type 有什麼關係?#

完全沒有關係

沒有統計學上的一致,你可以輕易的使用非常複雜且完備的 Type theory 做出爛的不行的語言。

之前談的話確實有語法優勢和型別簡單的優勢,但現在沒有用 text editor 寫程式了

過於靈活的語言無法寫出良好的 IDE 插件,如 Racket 的 syntax macro 可以隨便變更語法,如 reader macro 等

如 Ruby 到現在也沒有良好的補全因為執行時生成大量的程式碼。

還有就是說語言的不可靠沒有文件能不能寫程式的問題,舉個極端的例子,Haskell 程式設計師一般不需要任何註釋,看 type 就懂了,打個比方 Hoogle

图片 - 1024x202.png

我們這群程式設計師不用記任何名稱,只用記住他型別長啥樣子就行咯。

但是 Racket 程式設計師在寫複雜工程的時候沒有庫作者的幫助解釋他這是幹啥的是不可能寫好的。

還有一個至關重要的問題,工具鏈

才能決定這個語言容不容易用

打個比方說這裡有個反人類語言叫 Rust,它的語法醜陋,非常難寫,可是人家有 Cargo 這種世界一流工具鏈,所以才能大殺四方,要是這個工具鏈是 Haskell 的 stack 估計這個語言早就涼了。

trait XXX<T: Send + Sync + Clone> {
    type YYY<'a>: Future<Output = zzz::<AAA>::BBB<T>> where Self : 'a;
}

總結一下:Type 只能決定你能不能相信這個檔案裡躺著的程式碼的行為符不符合你的預期,Type soundness 的程度只能保證正確性而不能保證易用

為什麼你會認為有的語言比另一種語言好?#

每個人所遇到的問題都不同,所要解決的東西都不同,對正確性的要求也不同,我這麼 PL 的人不照樣部落格用 PHP 寫,你更應該關注使用什麼手段把事情做好而不是這個語言有沒有 type。

很多時候你說他好不好都是出於你的經驗,但問這個問題的人很大可能上並不是要做跟你相同的事情,你也不能夠保證自己的路徑是最優解,所以別亂推薦語言咯~

科研界 PL 人在幹啥?#

  • 造名詞🤫
  • 前往精神病院的路上🚑
  • 正在準備怼我🤯

結語#

希望大家理性看待程式語言,他們真的就只是最平凡的一種工具。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。