2012-07-29

动态语言应该有多动态?

Views: 22849 | 12 Comments

一加一等于几, 这是个问题

某些所谓的动态语言是名不副实的 - 我称之为伪动态语言. 这些伪动态语言之所以是伪的, 是因为它们只是在代码层面的变量是动态的, 而它们的类型系统并不是真正动态的, 一个简单的例子, 考虑字符串能否直接和整数进行拼接成为一个新的字符串.

当然, 语言维护者用另一个名词"类型强度(type strength)"来表示这种行为, 然后把这种本质上不动态的行为称为"强类型(strong typing)", 把真正的动态称为"弱类型(weak typing)".

但我认为, "动态语言"的概念应该重新定义, "动态"应该脱离字面的意义, 去探究真正本质的动态.

类型动态转换的动态语言

1 + "1" = ?

考虑"不动态"的 Java 语言的例子:

int i = 1;
String s = "1";
i + s; // ?

"i + s"应该表示什么? 是字符串拼接, 还是整数加法? 先跳过这个问题, 大部分被称为动态语言的编程语言都能这样表示:

i = 1;
s = "1";
i + s; // ?

大部分编程语言声明变量时不需要声明类型, 这种字面上的"动态"没有太多的用处, 象征意义更大. 虽然变量本身没有类型, 但还是会遇到刚才的问题, 到底是字符串拼接整数加法? 看看主流的编程语言是如何处理的:

编程语言 行为
Java 编译时异常
Python 运行时异常
JavaScript 字符串拼接
PHP 整数加法

Java 的表现很容易理解, 但 Python 却报运行时异常, 显然, Python 不够动态. JavaScript 看到只要有一个参数是字符串, 就认为是字符串拼接, 这样预期就可以固定(某些语言根据参数的顺序来动态决定是何种操作, 导致有不同的预期). 而 PHP 另辟蹊径, 使用点号(".")符号来表示字符串拼接, 完美地解决了决策问题.

当然, 某些人并不认为 PHP 的解决方案是完美的.

动态成员的动态语言

对待 a.b.c 的态度; null 也是对象.

对"a.b.c"的处理方式决定一种编程语言是否是动态的. "a.b.c"表示对象 a 的 b 成员(也是一个对象)的 c 成员. 如果要操作 a.b.c, 不同的编程语言如何处理?

Object a = null;
Object v = a.b.c; // ?
编程语言 行为
Java 编译时异常
Python 运行时异常
JavaScript 运行时异常
PHP v = null

Java, Python 和 JavaScript 都报了异常, 只有 PHP 能正常执行(假设关闭了 E_NOTICE). 这一个小小细节, 体现了一种编程语言的(对程序员)友好程度. 对于报了异常的语言, 程序员必须繁琐地进行"是否定义"的判断(也就是防御性编程), 例如 JavaScript:

a = null;
if(a != undefined && a.b != undefined && a.b.c != undefined){
	v = a.b.c;
}

而 PHP 却非常简单:

$a = null;
$v = $a->b->c;

PHP 处理方式有什么好处? 假设 a 是用户的 profile, b 是用户的配置, 而 c 是用户配置的其中一个配置项, 表示用户是否接收邮件通知. 那么, 业务上会有两种考虑: 是否需要用户明确地表示其接受或者拒绝之后, 才做判断是否发送?

如果业务需要, 用户必须配置过这个选项之后, 才决定是否发送邮件, 否则不发送(默认不发送). PHP 可以简单地判断:

if($a->b->c){
	// sendmail
}

或者业务需要, 只要用户不拒绝, 就发送邮件(默认发送). PHP 还是可以简单地判断:

if($a->b->c !== 0){ // 用了强类型判断
	// sendmail
}

PHP 的这种能力叫做"和业务逻辑的简单对应", 也就是说, 人的每一项思维都可以用编程语言的一个表达式来很好地表示, 这才是真正的动态语言. 我想, 这也是 PHP 为什么如此流行的原因(我以前从不同的角度谈过PHP的优势). 当然, PHP 还有一些缺点, 例如不够对象化, 函数不是对象, GC 不成熟等.

所以, 我们还是需要一种新的动态语言, 但应该是足够"动态"的.

后记

脱离低级趣味的语言之争.

类型系统是编程语言最本质的因素, 语法是其外衣, 而类库的丰富程度是语言自身能力的最直接体现.

类型系统才是编程语言是否接近人类思维的判断标准, 而某些编程语言把关键字"null"改成"nothing", "{}"改成"begin ... end"类似的大量使用英文单词的做法, 无非是一种无关紧要的个人喜好, 如果非要说成是对人亲切, 那就是本末倒置了. 我们写"a * b", 而不是写"甲乘以乙", 就是同样的道理.

Related posts:

  1. 用C语法来写Python代码
  2. PyPy – 吞下自己尾巴的小蟒蛇
  3. 开始学习 Python
  4. SSDB 现在已经支持 Java 语言了!
Posted by ideawu at 2012-07-29 01:00:33

12 Responses to "动态语言应该有多动态?"

  • Python的类型系统实际上是真正的动态类型。

    试试下面的代码:
    type(‘a’)

    再试试:
    type(type(‘a’))

    没错,只存在一种类型,type.

    而以前,’a’ + 1 这样的行为是完全被允许的,不同类型比较大小也是可以的,但是,由于这样经常导致程序的错误,于是Python的限制就越来越严格了,但本质上还是动态类型。 Reply
  • 添一字:static type checking/dynamic type checking,这样歧义更少。Java和Python的处理方式我看来是这两个世界应有的处理方式。施主是觉得JavaScript和PHP这种隐式的方式更好吗?虽然省了些代码,但是更容易出错了。 Reply
    @MaskRay: 在我所举的例子中, 隐式的确实比显式的更简洁. 最开始如 C 语言, 每一个变量名只能指定特定类型的数据, 后来如 Python, 一个变量名可以指向任何类型的数据. 为什么从显式的声明变量类型到隐式地动态地决定变量的类型? 虽然很多东西仍然需要 int i = 1; 但我们知道同时有许多情况只需要 i = 1; 这就是某些方法解决某些问题的原则. 有时我们需要语言和编译器帮我们检查, 有时我们不需要. 脱离场景空谈是无用的. Reply
  • 你举的例子,Python显然是要放try块里。

    PHP的处理方法未必是最优。Explicit is better than implicit. Reply
    @yegle: 其实无论是try还是if判断, 都是要做大量的判断, 而大部分的判断都是可以省略的. 写过实际业务处理的js的程序员肯定有深刻体会, 防御编程过度了, 程序员也会想吐. 这时, implicit is better than explicit. Reply
    @ideawu: Assert和Exception catch可以方便地进行防御编程。建议你还是先学习exception吧。 Reply
    @yegle: 他根本连隐式和隐喻都分不清,就开始满嘴胡说,有啥好讨论的…… Reply
    @yegle: 把"Explicit is better than implicit"挂在嘴边的人是愚蠢的, 只有懂得"有时隐喻比显式好, 有时显式比隐喻好", 并且知道在哪些情况下各符合哪一者, 才是真正懂的人, 否则只是可悲的鹦鹉学舌. Reply
    @yegle: 没必要吊书袋, 难道异常是个很高深的玩意? 一会又是引用某些特定环境下成立的话, 就以为是普适真理了? 你这样迂腐的样子才真是应该接受我的建议去学习学习吧. Reply
  • Twitter 观光党前来围观。
    动态/静态、强类型/弱类型是编程语言的两个重要指标。居然连这种基本概念都能混淆……果然奇葩。 Reply
  • http://en.m.wikipedia.org/wiki/Dynamic_programming_language
    建议楼主先去看看定义,业界对动态语言这个定义的共识,并不包括它一定要是弱类型系统。请不要偷换概念 Reply
    @ayanamist: 我的观点是重新定义动态语言的概念, 改变现在的共识. Reply

Leave a Comment