作者electgpro (Ray)
看板Soft_Job
标题Re: [讨论] 请大家聊聊静态语言的缺点
时间Tue Nov 24 09:45:22 2020
借题发挥一下: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://webptt.com/cn.aspx?n=bbs/Soft_Job/M.1606182325.A.2CA.html
※ 编辑: electgpro (82.25.26.57 英国), 11/24/2020 09:48:00
1F:推 CoNsTaR: typecheck 对於成功 type checked 的程式码的关系就相当 11/24 10:05
2F:→ CoNsTaR: 於 compile 对於成功编译出来的执行档的关系一样 11/24 10:05
3F:→ CoNsTaR: 计算和类型本来就是等价的,不知道为什麽有很多人在讨论 11/24 10:05
4F:→ CoNsTaR: 静态型别的优缺点,但都没看到有人在讲编译式语言的优缺 11/24 10:06
5F:→ CoNsTaR: 点 11/24 10:06
6F:推 CoNsTaR: 强型别对程式码的好处不就像是编译式对程式的好处一样吗 11/24 10:08
7F:→ CoNsTaR: ? 11/24 10:08
8F:→ electgpro: 理想上同意,但实务上可能会有一些诡异的状况 11/24 18:45
9F:推 zero11995: 推 12/01 11:12