`

动态语言的尴尬

阅读更多

一提到动态语言,一般都会想到像 Python、Perl 以及 Ruby 之类的语言了,按照 Wikipedia 上的定义,动态语言是这样的:

Dynamic programming language is a term used broadly in computer science to describe a class of high level programming languages that execute at runtime many common behaviors that other languages might perform during compilation, if at all. These behaviors could include extension of the program, by adding new code, by extending objects and definitions, or by modifying the type system, all during program execution. These behaviors can be emulated in nearly any language of sufficient complexity, but dynamic languages provide direct tools to make use of them.

动态也不是说着玩的,一般 dynamic programming language 都是 dynamic typed ,换句话说:变量无类型,而值有类型。像以下的代码当然是基本要求了:

a = 12;
a = "foo";

当然还有其他动态的地方,比如,如果语言是面向对象的,那么对象的特征甚至类型通常都可以在运行时改变,甚至类也可以多次被“打开”进行修饰和修改,总之就是想怎么变就怎么变,让人写起程序来跟捏泥巴似的,哪儿不像了揉一下重新捏。再换个说法,动态语言之于静态语言,就好像它引入了时间,而不在是静止的了。静态语言编译好之后就是那个样子了,而动态语言得到的东西说不定过一会儿就和刚才不一样了(当然事情不是那么绝对,因为即使是静态语言也可以修改自己的二进制代码,关于这一点,甚至有关系到动态语言的定义的争论)。

然而动态语言这种特性却也有尴尬的一面,因为它让源代码变得“不可信”了。

在开源社区里面有一个普遍的观点:源代码是最好的注释。注释有可能(并且通常是)滞后于源代码,更关键的是,源代码没法骗人,代码怎么写,程序就必然是那个样子的了。而现在到了动态语言里面,这招不好用了,比如,在 Rails 里面,那些 model 通常是一些空类,但是你却看到在其他代码里面调用它们的许多乱七八糟的方法,而且这些方法在父类里面也没有定义:函数就这样凭空造出来了!真神奇!现在什么 grep ,TAGS 通通都不灵了!比如在 Pascal 里面,你可以搜索“function”就得到关于函数定义的语句。而在 Ruby 里面呢?比如,要找函数 foo ,可能可以搜索 def *(self.)?foo ,这是比较常用的定义函数的方法了,用简单的文本搜索工具就可以搜索到。但是定义函数的方法远远不止这一种啊。

在 Ruby 官方文档的 define_method 的文档里面有这样一个例子:

class A
  def fred
    puts "In Fred"
  end
  def create_method(name, &block)
    self.class.send(:define_method, name, &block)
  end
  define_method(:wilma) { puts "Charge it!" }
end
class B < A
  define_method(:barney, instance_method(:fred))
end
a = B.new
a.barney
a.wilma
a.create_method(:betty) { p self }
a.betty

可以看到这里定义的四个方法分别是用不同的方式来定义的

  • fred 采用传统的 def 进行定义。
  • barney 使用 define_method 以另外一个方法为蓝本进行定义。
  • wilma 使用 define_method 和 block 的方式进行定义。
  • betty 使用自己定义的一个 create_method 方法进行定义。

到这一步,简单的文本搜索已经不管用了,必须要对代码进行语意分析才行了。再过分一点,把上面的 symbol 换成使用字符串的方式,字符串再动态拼接一下,完了,语意分析也不行了,非得执行一遍才行。再过分一点,字符串需要用户交互产生,完了,无法在后台执行,或者,字符串从数据库里面来,或者其他有可能随时间变化的源头产生,甚至是与时间本身有关,就彻底完蛋了,除非在真正用户要执行代码的那一刻,否则分析出来的结果都是假的了。

类似的,像在 Lisp 这样的语言里,函数其实就是一个对象(lambda),与它的“名字”其实没有什么必然关系:

(define (foo a)
  (display a)
  (newline))

其实和

(define foo
  (lambda (a)
    (display a)
    (newline)))

是等价的。就是说,拿着一个“函数”(lambda),我可以随时把它“赋值”(bind)给某个“变量”(symbol)或者其他的变量。再让 Lisp 里面引以为傲的 macro 来凑一下热闹,函数的“根源”就更加无处可循了。

事实上 Lisp 采用一种增量式开发的方式:在一个交互环境定义一些函数变量一类的,并随时进行更改,因为一切都在运行时是可更改的,而这个交互环境就是正在运行的程序,因此一切都是“真实”的。结束以后将当前的整个环境 dump 成一个新的 core ,下次可以直接加载那个 core ,再进行相应的添加和修改,可以说是从最初一个基本的 Lisp 解释器增量式地进化为自己专有的程序。事实上动态语言大多都有非常强的“反射”功能,并且将程序注释作为程序的一部分,比如可以查看到某个函数说附带的注释(或者说,文档、说明),这在一定程度上算是替补了源代码的地位吧(其实如果能动态地根据函数查到它的源代码的话,似乎更舒服,当然,在 Lisp 这种“代码和数据是同样的东西”的语言里面,这几乎就是 trivial 的啊)。

其实我把这看作是动态语言尴尬的一面吧,起因是我在一个有点大的源码树里面找一个函数的定义的悲惨经历。我不知道有没有更好的解决办法了,要不然真的很尴尬。

其实我比较奇怪,Refactor 发源于 Smalltalk ,而 Smalltalk 也被 wikipedia 归到动态语言一类里面,而 Refactor 则是对源代码进行更改,并且据说 Smalltalk 的 IDE 在 Refactor 方面表现得非常智能。我就想着,如果光调用一个函数的方法就有千万种( 什么 call、send、apply、eval 一类的 ),那我要做一个“给函数改名”的重构,不知道这个 IDE 究竟要如何来做了?可惜我不会 Smalltalk ,有机会一定要去见识见识了。 :)

分享到:
评论

相关推荐

    网络语言的发展及演变.pdf

    7. **调侃和幽默**:网络语言常常带有调侃和幽默的成分,例如“囧”字在网络上代表尴尬,形成了独特的网络语境。 8. **直观化**:网络语言倾向于直观表达,比如使用“给力”来形容非常棒,“吐槽”表示批评或抱怨,...

    小学语文知识关键时刻可以玩些语言小花招

    首先,文章强调了语言的动态性和情境性。在特定的语境下,没有任何一种固定的表达方式能适用于所有场合。因此,能够根据不同的场合和对象灵活地运用语言,是沟通中的一个重要技巧。而这些所谓的“语言小花招”,实际...

    qq原版动态表情

    这些GIF格式的表情包通常包含了一系列精心设计的动画,涵盖了各种情感和情境,如喜悦、惊讶、疑惑、尴尬等,使得在聊天中能够更直观地表达用户的心情和态度。下面将详细探讨QQ动态表情的各个方面及其在IT领域的应用...

    51单片机万年历时钟汇编语言实现

    操作:在主程序待机运行中,按下按键2,主程序进入日期显示(动态),默认显示方式为日期时间跳变显示,按1键在三种模式间切换,具体效果如下: 模式一日期、时间跳变切换效果:显示时间(4秒)=&gt;显示年(1秒)=&gt;显示月日...

    JavaScript设计模式之单例模式实例

    不管是弱类型或强类型,静态或动态语言,命令式或说明式语言、每种语言都有天生的优缺点。一个牙买加运动员, 在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些。 术士和暗影牧师很容易成为一个出色的辅助,而一...

    Unity-Learn:我制作独立游戏的尴尬尝试

    JavaScript是一种动态类型的脚本语言,对于网页开发尤其常见,但在Unity中,它提供了与C#相似的功能,让开发者能够编写游戏逻辑。 在尝试制作独立游戏时,开发者可能会遇到以下一些关键知识点: 1. **Unity基础**...

    AJAX技术学习总结分享.pdf

    Ajax技术的应用也使得微软感到尴尬,因为微软早在1997年就已经发明了Ajax中的关键技术,但是却没有看到它的潜力而加以发展和推广。 六、Ajax技术的优缺点 Ajax技术的优点是可以提高网页的交互性和响应速度,提高...

    jdk1.7 32位官方正版版

    9. **动态语言支持**:Java 7引入了 invokedynamic 指令,为动态语言如Groovy、JRuby等提供了更好的支持。 在"压缩包子文件的文件名称列表"中,我们看到一个文件名为"jdk-7u80-windows-i586.exe"。这个文件是JDK ...

    4clojure-solns:我对 4clojure 的解决方案,因为它们喷涌而出。 其中有些是彻头彻尾的尴尬! 不建议观看

    提到“有些是彻头彻尾的尴尬”,这可能是指早期的解答不够优雅或者效率低下,甚至可能有错误。作者不建议直接查看这些解答,可能是出于教学目的,希望学习者能够自己独立解决问题,或者至少先尝试解决后再参考答案。...

    饭桌上的争论作文.doc

    8. **语言的动态性**:即使是受过高等教育的家长也可能对某些词汇的发音有误解,这反映了语言的复杂性和持续学习的必要性。 总的来说,这篇作文揭示了学习过程中的互动、挑战、乐趣以及家庭环境对孩子成长的影响,...

    Javascript实现的断字hyphenation算法

    在没有适当的断字时,长单词可能会导致行尾出现尴尬的空白或者使得单词跨越两行,影响整体的阅读体验。Hyphenation算法就是解决这一问题的方法,通过在适当的位置插入破折号(-),使单词能够适当地在行尾断开。 在...

    2013-2014学年高中语文 3.9《一碗阳春面》同步测试 沪教版必修1

    “尴尬”在文中指人物在某些场合下的不自在或为难的心理状态。“摇曳”用于形容事物的动态美,也暗示了人物内心的波动。“奢侈”在文中并非指浪费,而是指人们在特定时刻的微小奢侈,如享受一碗热腾腾的面条。“屏住...

    高二语文试卷高中语文第四册第二单元测试题[精选].doc

    “不尴尬”是正确的词组,而“不尴尬”是错误的。 4. 成语运用:成语是中国文化的重要组成部分,正确理解和使用成语是语文学习的关键。如题目中提到“不经之谈”和“举国一致”,需要理解其含义并判断是否适用于...

    交规考试-沟通技巧期末考试题_1.docx

    3. **拒绝技巧**:**入瓮拒绝法**是一种策略,通过设置逻辑前提,让对方自己得出否定的结论,避免直接拒绝的尴尬。 4. **开场白技巧**:**攀认式开场白**是在交谈中寻找与对方的共同点,以此建立亲近感。 5. **...

    old-article-warning:如果您正在阅读一篇旧文章,请警告您,以免在社交媒体上让自己尴尬!

    JavaScript是一种广泛使用的编程语言,特别适合用于构建Web前端交互和动态功能。在这个场景中,JavaScript可能被用来检测用户访问的页面是否包含过时的文章,并显示相应的警告提示。开发者模式允许程序员直接加载未...

    The C++ Programming Language

    3. **异常处理**:C++的异常处理机制允许程序员在程序中捕获并处理错误,避免了因错误处理代码打断正常流程的尴尬。try-catch语句块使得异常处理变得有序和整洁。 4. **命名空间**:命名空间是用来组织和管理代码的...

    android应用-把妹笑话

    "android应用-把妹笑话"是一款专为提升社交互动和娱乐而设计的应用,它集成了丰富的幽默和诙谐的笑话,旨在帮助用户在与异性交往时增添乐趣,打破尴尬,或者简单地为日常生活带来欢笑。下面我们将深入探讨这款应用...

    pkuhw01 answer

    短信延迟发送功能让用户拥有了一次“后悔”的机会,能够有效避免因误操作发送不适当信息的尴尬场景。而国旗快捷切换语言功能,则考虑到了非母语用户在使用过程中可能遇到的语言障碍问题,大大简化了语言切换的步骤,...

    2015届高三语文优秀作文集锦国庆素材

    例如,“罄竹难书”用来形容国庆出游时人山人海的盛况,“黔驴技穷”则被巧妙地运用在描述某家人出游时遇到的尴尬困境。成语的丰富内涵与作者的巧妙构思结合,使得文章在幽默之余,更显得风趣生动。 接着,讽刺与...

    X3-BLOG 博客源码

    度远远超过了市面上所有的BLOG产品,有效的减轻了服务器的带宽压力,服务器端使用四大动态网站开发语言中速度 最快的ASP.NET(C#)编写,屏弃了传统的控件开发方式,所有执行过程采用单向流的生成方式,使其对服务器...

Global site tag (gtag.js) - Google Analytics