`

动态语言的尴尬

阅读更多

一提到动态语言,一般都会想到像 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;显示月日...

    宁夏固原一中五原补习部2021届高三下学期5月第三次冲刺考试语文试题 Word版含答案.docx

    文章指出,有些人认为表情包可能损害了人们的表达能力和语言,因为过度使用和误解表情包可能导致沟通困难和尴尬。然而,另一方面,有数据显示很多人在日常交流中对表情包产生了依赖,甚至美国国会图书馆收藏了完全由...

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

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

    QQ经典表情105个【原版打包】

    而在表达歉意或尴尬时,“害羞”或“抱歉”的表情则可以减轻语言的生硬,让对方更容易接受。 此外,QQ表情的流行也催生了一种独特的网络文化,许多网友会创作和分享自定义的表情包,以表达更个性化的情绪。这些原版...

    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算法就是解决这一问题的方法,通过在适当的位置插入破折号(-),使单词能够适当地在行尾断开。 在...

    三年级语文下册第五单元17我变成了一棵树精彩片段素材新人教版20200511265

    "冒出来"则形象地表现了树枝生长的动态,增加了故事的趣味性。教师鼓励学生通过朗读表达这种新奇与惊喜的情感。 其次,教师带领学生探讨课文中关于形状各异的鸟窝的描写,利用省略号启发学生思考可能的其他形状,...

    如果你跟夕小瑶恋爱了---(上).pdf

    隐马尔可夫模型是一种统计模型,广泛应用于自然语言处理、语音识别、生物信息学等领域。在这个模型中,存在两个关键概念:隐状态和观测值。隐状态是无法直接观察到的内部状态,只能通过观测值间接推断。在夕小瑶的...

    【小学生作文】小学生有趣的一件事作文200字.doc

    2. **情感表达**:文章中体现了小作者们的情感变化,如摘草莓时的兴奋、抓鱼过程中的挫折与乐趣、与家人共度时光的快乐以及摔倒后的尴尬和幽默。情感的真实流露使故事更富有人情味。 3. **情节设置**:每个小故事都...

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

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

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

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

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

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

    The C++ Programming Language

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

Global site tag (gtag.js) - Google Analytics