看板 Soft_Job 關於我們 聯絡資訊
借題發揮一下:static typed for the win 不過還是先切題回答「靜態語言的缺點」: 在大部分常用的靜態語言中,的確可能出現 valid program 不好標注 type 的情況 不過到底有多難標注就完全看是哪個語言跟哪個版本了 ----- 個人有碰過的語言依據學習順序大概是這樣 C -> Java -> Python/Ruby/JS/ObjC -> Scala/Kotlin -> Haskell/Idris (差不多時期學的用斜線表示) 我對這個問題的偏好也從「靜態」轉「動態」再轉回「靜態」 下面大概聊一下我在學習不同語言的時候的感想 ----- ##「靜態」轉「動態」 - Java -> Python,覺得 Python 好方便,不用寫長長的 main,且不用宣告變數型態。 ## 在各種常見動態語言中遊蕩(? - 學了 Ruby 後覺得 map/filter 等等使用 block 的函數實在太方便了。而 Python 相對應的答案是 list comprehension。當時不明白明明可以用 Library 解決的問題, 為什麼要使用另外的語法,後來學了 Haskell 才完全了解這東西應該怎麼用, 不過這是另外一個話題。 - 學了 JS 後覺得 Ruby block 語法比較沒有一致性,在 JS 全部用 anonymous function 就解決了。也大概在這個時間點了解所謂 first order function 是怎麼一回事。 因為差不多在這個時期同時有在接 Android/iOS 專案,所以 Java/ObjC 碰得不少。 ObjC 雖然有 lambda ,但語法異常複雜以至於有這個網站 http://fuckingblocksyntax.com/ 而當時 Java 才剛開始有 lambda solution,必須要靠 compiler plugin 才能支援, 但還是 desugar 成 class Function<T, R>,所以在 Java-like lang 寫 lambda 要標註 function type 實在醜,所以在這個時期最喜歡的是支援動態型別、 first order functions 的語言 JS。 ## 「動態」轉「靜態」 不過上述問題在 scala/kotlin 等新興語言都有改善。以下是不同語言的 map function 比較: - Java 8: List<R> map(Function<T, R> f) - Scala: def map[B](f: (A) => B): List[B] - Kotlin: fun <R> map(f: (T) -> R): List<R> - Haskell: map :: (a -> b) -> [a] -> [b] 基本上大部分的情境中 function type annotation 現在應該都不是什麼大問題 當然 OO Lang 還要考慮繼承,所以還有 variance 的問題(不過在這邊就先忽略不談 ## Type Annotation 很花時間是指? Type inference 現在應該都是基本了,所以宣告變數需要重複寫 type 應該已經不是 個問題了。其他常被提到的則跟 sum type/product type 有關。 Product type 基本上就是一個 class 有多個 value members。但 Sum type 大家可能就 比較不熟悉。 舉例來說,一個 function 他需要同時支援 type A 跟 type B 作為唯一的 argument 基本上我知道的語言中,大概有三種方式: 1. 讓 A, B 實作同一個 interface/super class 2. Union Type, typescript/flowtype: type AorB = A | B 3. Tagged Union Type, Haskell: data AorB = A A | B B 其中 scala/kotlin 屬於 1. 但不像 Java 一樣宣告起來麻煩: sealed abstract class Base case class A() extends Base case class B() extends Base 當然還是比 Haskell 的一行多了一些。而 TypeScript 更可以 inline 宣告。 到這邊為止,大部分的語言應該在九成五的 case 都不需要太多成本就能 cover 了。 ## Haskell/Idris 當然還是有某些狀況下,type 很難被正確 annotate,例如如果 input 小於某個數字, 就回傳 String 否則回傳 Int。雖然可以用上面提到的 sum type,但是如果我們確定 input 一定大於指定數字,所以不想要處理 String 作為 output 的話,那就要用到 dependent type 了。 而如果使用有 dependent type 的語言,絕大多數的 program 都可以被 annotate 不過問題是: 1. 學習門檻高,大部分的基礎程式課程連 generic 都不會講,更不用講 DT 2. 大部分的語言不支援 DT ## 結論 靜態語言跟動態語言只是一個非常粗略的分法,其中可以討論的面向從純技術層面 到團隊營運跟產品性質都有關係。如果可以在討論的時候舉一些例子會比較有趣 :D 不過一般來說我還是覺得靜態語言比較好一些。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 82.25.26.57 (英國) ※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1606182325.A.2CA.html ※ 編輯: electgpro (82.25.26.57 英國), 11/24/2020 09:48:00
CoNsTaR: typecheck 對於成功 type checked 的程式碼的關係就相當 11/24 10:05
CoNsTaR: 於 compile 對於成功編譯出來的執行檔的關係一樣 11/24 10:05
CoNsTaR: 計算和類型本來就是等價的,不知道為什麼有很多人在討論 11/24 10:05
CoNsTaR: 靜態型別的優缺點,但都沒看到有人在講編譯式語言的優缺 11/24 10:06
CoNsTaR: 點 11/24 10:06
CoNsTaR: 強型別對程式碼的好處不就像是編譯式對程式的好處一樣嗎 11/24 10:08
CoNsTaR: ? 11/24 10:08
electgpro: 理想上同意,但實務上可能會有一些詭異的狀況 11/24 18:45
zero11995: 推 12/01 11:12