scala雾中风景(26): 变量查找的问题

在Java/Scala的一个方法里,存在与全局变量同名的局部变量的话将会覆盖这个全局变量,但当在这个方法局部变量定义之前就引用这个变量,在Java和Scala的编译器里给出了不同的实现,先看Java里:

➜  cat B.java
public class B {
    static String name = "noname";
    public static void main(String[] args) {
      System.out.println(name);
      String name = "wang";
    }
}

➜  java B
noname

在main方法里第一行引用的name是全局变量,在同名的局部变量定义之前它从全局查找这个变量。而在Scala里:

 ➜  cat A.scala
object A {
    val name: String = "noname"

    def main(args: Array[String]) {
        println(name)
        val name = "wang"
    }
}

 ➜  scalac A.scala
A.scala:5: error: forward reference extends over definition of value name
    println(name)
            ^
one error found

编译时错误,它优先从方法内部的局部变量表类查找了。我更接受Java里的方式,而且这种方式已经深入人心了,对Scala为何这样做我不清楚是出于什么考虑,是有意这样还是实现上的bug?

yield的字面意思

Geek Talk里的一段对话,关于yield这个单词是否在所有编程语言里都是相同的含义。出于隐私,隐去了讨论者名字。不对讨论内容的正确性负责。

W:各位,我请教一个英语问题,yield 这个词语有几个意思?我最早是在Java里,Thread 有个 yield 方法表示 当前线程让出cpu,让其他线程先执行。yield 在这里的意思是“屈服, 放弃,让出”。后来在 C# 里,迭代器的实现可以用 yield return ,我当时就对 C# 里的 yield 和 Java 里的 yield 在意思上有没有相同的根源产生过怀疑,但没深究,就把它当作“产生,生成” 的意思来理解的,(我不确定我当时的理解对不对),后来在 Scala里 for推导里也有 yield 关键字,我也同样当作“产生,生成”的意思来理解。最近看到lua 的 coroutine里也有 yield ,我觉得可能它们是有相同或相似的根源的,只是我没有get到,这几种语言里 yield 所表达的,跟操作系统的线程原语 yield 是不是都是一个意思呢?

Y:是同源。因为Java刚出来时,Linux还没有线程那时候Unix有make_context,相当于非抢占的协程,所以Java的yield是为了给这些操作系统用的,但实际上到头来并没用上。

R:我一直认为c#里yield是生产、生成的意思,因为它只能用于实现IEnumerableyield后面必须跟return<element>,或者break,代表生产终止

W:我的英文不太好,所以我在猜测,到底这个词本身就确实有很多意思(就像中文里的“打”这个字不同上下文不同的意思),在这几种语言里 yield 也是不同的意思呢,还是 我们误解 C# 和 Scala 里的 yield 其实也是 “屈服、让出” 的意思(背后其实是流控上的含义?)

W:协程本质上是一种流控,我这么说有没有问题?还是说流控是协程实现手段之一更合理

Y:yield这里是专有名词,意思就是让出的意思,不过词源我不清楚。

W:从我了解到的 yield 这个关键字在多数语言里(C#, Scala, Python)里应该都是“生产、生成”的意思,而跟 java 里表示线程的 “让出”,完全不搭边。但在lua的coroutine 里 yield 又跟 Java线程的 “让出” 意思一致

M:感觉是动作的对象不一样而已吧

W:scala / python 里的 for comprehension 里的 yield 如果也是“让出”的意思而非“生产”的意思,还是有违背直觉的,尽管从 Control flow 上能解释的通

W:一切用到 yield关键字 的编程语言,含义都可以归纳为“交出控制权”?

S:伙计,我说一下现实生活中yield的例子,可能对你有帮助。在美国的公路上碰到yield的路标都表示在前方汇合点你要让行,如果没有车你可以并线。

W:这个例子解释线程的yield原语没有问题,但对 for-comprehension 或迭代器里的yield又怎解释呢?

W:补充给python程序员,Scala 里的for-comprehension跟 Python 里的list-comprehension是一回事,只不过更泛化。

G:to yield is to give up (something you own) on demand / claim. 我觉得如果从这个含义出发去解读,不论是线程(竞争中的个体)“让出”控制权(放弃抵抗或者内心执念),还是迭代器(农作物)“产出”值(粮食)都 make sense。 #my2c

W:这正是我觉得有所不对劲儿的地方,因为编程世界里通常是不太会出现 具有多重意思(含混)的 英文单词的。所以有可能是我们误解了 yield ,没有真正理解清楚。我现在偏向于,它在所有上下文里都是统一的含义:保存当前上下文(比如栈),让出执行权。

L:我觉得你的理解没错呀,yield更像是个受控的goto

G:我觉得yield这个词虽然有多种具体的释义,我直观感觉其内涵是一致的,只不过确实抽象了些,这让我想起英语和汉语的某些根本性的差别(抽象 vs具象,不定性vs定性)。可能有人会觉得我接下来的解释太过牵强,不过anyway我还是说了:这种抽象就像monad,它抽象了一种行为特征,同时任何一种具象的实现都不能完全表达出这种抽象,但每个具象的实现都能让我们更容易理解它(或者说让它更贴近我们实际遇到的事物),因此尽管释义多种多样,干的部分是相同的。也许扯远了,我并不确定Java线程的设计者和python的迭代器的设计者在当初选择yield这个词的时候是不是背后有相同的/相通的(其含义机械且确定,没有二义性的)计算机概念,我更倾向于相信是因为英语中这个动词准确的把表达出了线程和迭代器各自上下文里的各自的、具象的含义。即:从英语来说这两种释义它们是同源的,从计算机具体的、特定的概念来说,它们未必是。

J:第一次看到这个词是在Python,我觉得它的意思是喊一声。生产完对象喊一声,不用CPU了喊一声

W:也可能是我想多了,或许这两个语境意思并不统一,这也是我们母语非英语的程序员的一大问题,在捕获信息时需要付出更多的代价才能确定其准确性。

L:ruby里面有两个地方有yield,一个是method去call传入的block,一个是fiber出让调度,本质上都是切上下文,所以我觉得你没想多

Z:这个…你想多了吧,yield 在现代英语里本来就有这两意思。我还去查了 etymology dictionary. ld English gield “payment, sum of money; service, offering, worship;” from the source of yield (v.). Extended sense of “production” (as of crops) is first attested mid-15c. Earliest English sense survives in financial “yield from investments.”

西撒克逊古英语的gieldan和盎格鲁语geldan 都来自古日耳曼语的geldan, 有pay, to repay, return的意识。到14世纪早期,在投资中得道回报,也有survives in financial的意思,发展成了survives, give oneself up, surrender 的意思。 15世纪中叶gieldan另一分支,耕作谷物得道回报,发展成了production的意思。

Q:在国外开车除了停车线stop有时会遇到让车线yield。就是如果有直行车辆正在通过,停在那里等,否则进入车道。我想在for comprehension 里应该是差不多的意思,执行for里面的sequential functions,当所有functions 都被执行,弹出结果。

G:这是个好问题,专门去复习了一下python的generator语法:yield本质上就是“让出”但不“退出”,由于整个计算还没有结束(就好比generator说:我还不能死,还得保留当前状态),故不能return。

W:javascript 里 yield 明确的含义就是“让出”,python 也是。所以 c#/ scala 这种后出的语言,基本都是“拿来主义”,尽管未必是那个含义,也是把其他语言里已经被大众所熟知的语法直接拿来。

W:scala 里的 for-yield 是个语法糖,跟 js/python 里的generator 完全无关,要实现类似generator效果需要用 lazy/Stream 等惰性计算的特性。

W:我认为 C# 里的 yield 也是 “让出” 的意思,你可以跟 C# 开发者确认一下。

W:我知道这个词有多个意思,只是在程序语言里,是不是都代表一个意思,还是代表的是不同的意思,这才是我疑惑的。

R:C#里也是延迟执行的,迭代到了才执行生成对应的item的代码。这也是让我觉得像produce的原因

Java/Scala程序员书单

这里列一些对Java/Scala程序员有帮助的书单,先随意记录一些,后续有空会分类一下并补充更多的评价。

《软件框架设计的艺术》
这是Netbeans的创始人写的一本很有价值的书,里面的边角细节也很有料。国内市场上没有对这本书给予应给的赞誉。

《Effective Java 第二版》
被称为Java领域的圣经,小中见大。探讨的不仅仅是Java语言,也包括一些形而上的东西,取决于读的人理解多少。我在面试时喜欢考察一些基础的东西,以及背后的想法和初衷,可惜相当多的程序员这本书都没仔细阅读过。

《并发编程实践》

《Java并发编程》

《Java 并发编程设计原则与模式》

《代码的未来》

《Programming in Scala》
中文版是”Scala编程”,对scala程序员来说这本书你不能不读

《Java解惑》

《深入Java虚拟机》(原书第2版)
有些过时了

《Java与模式》
十几年前正是模式刚流行的时候,阎宏博士的这本书当时在中文圈里引起了很大反响,这本书算得上一本经典巨著。

《观止-微软创建NT和未来的夺命狂奔》
好些年前从温绍锦那儿借来看的,忘了还给他。介绍了NT的开发过程,写给大众看的,偏故事性,读起来很过瘾。

《程序设计语言》第三版

《重构》

《Java Rules中文版》

《企业应用架构模式》

《领域驱动设计》

《Java虚拟机规范(Java SE 7版)》

《Java程序员修炼之道》

《HTTP权威指南》

《TCP/IP详解卷1:协议》

《TCP/IP详解卷2:实现》

《构建高性能Web站点》

《JAVASCRIPT语言精髓与编程实践》

《深入剖析Tomcat》

《Maven实战》

《哥德尔、艾舍尔、巴赫:集异璧之大成》

《An Introduction to Functional Programming Through Lambda Calculus》

《分布式系统概念与设计(原书第3版)》

《实用Common Lisp编程》

《面向模式的软件架构 卷1:模式系统》

《面向模式的软件架构 卷2:并发和联网对象模式》

《面向模式的软件架构 卷3:资源管理模式》

《面向模式的软件架构 卷4:分布式计算的模式语言》

《面向模式的软件架构 卷5:模式与模式语言》

《编程语言实现模式》

《架构之美》

《精通正则表达式》

《浪潮之巅》

《多处理器编程的艺术》

《JAVA核心技术卷II:高级特性》

《Java核心技术 卷I: 基础知识》

《程序员修炼之道——从小工到专家》

starling和kestrel这两只鸟的来由

虽然SK组合子早有所闻,但这两个字母所代表的意思却一直不知道,原来是出自于《To Mock a Mockingbird and Other Logic Puzzles》这本书,作者用starlingkestrel这两只鸟来演绎哥德尔的证明。SK是这两只鸟的缩写,我是看到这篇Blog才了解到的。

早先只知道starlingkestrel是twitter的消息中间件产品,原来产品名还有这个来由。