锁定老帖子 主题:Ruby Quiz
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-04-14
potian 写道 cookoo 写道 Trustno1 写道 @timeout = options["timeout"] || DEFAULT_TIMEOUT
按我这个行业的习惯,这样写真的很成问题.一来||的左右求值序到底是那种并不确定,依赖于语言和编译器解释器的实现.第二,如果 options["timeout"] 如果是一个函数运算,这个函数是不是执行依赖于||另外一端的求值以及编译器是不是进行截断求值,非常的可怕的写法. 在c是个问题, 在ruby不是问题, 呵呵. c 有问题吗,10多年用下来好像还是第1次听说 比如说这种代码把 bool c=a==true||do_something()==false; 这种代码就是二义性的.do_something到底是不是执行,仰赖于a的取值.你不能保证在有side effection的情况下,a的求值总是满足do_something的调用条件. 而且在某些安全性的情况下,比如说我通过内存溢出的漏洞,覆盖a的值,那么就能控制do_something的执行.这是一种非常危险的写法. 所以我的倾向是,||,&&只用于bool型变量的运算,而不要带任何函数返回值的运算. |
|
返回顶楼 | |
发表时间:2006-04-14
1. 不管是用Ruby写还是用Java写,良好的编程和阅读习惯都不需要指明类型,因为上下文已经说得很清楚了,如果你这样去阅读代码,恐怕一天读不了几句话.代码可理解性的关键在于明确表达你的逻辑和计算意图,匈牙利命名法在这一点上是有害的,你必须首先把变量中的类型部分去掉,才能开始阅读真正的代码含义.最可读的代码是最接近自然语言,不包含缩写(或者只用众所周知的缩写)
2. 你恐怕搞错了动态和强弱类型之间的区别 Ruby虽然是动态语言,但它却是强类型的,它当然知道这是一个Hash.关于副作用,我不懂什么意思,这是写代码的人决定的,有时侯确实需要利用副作用,这和可读性有什么关系. 你讲的对称性我也不理解 |
|
返回顶楼 | |
发表时间:2006-04-14
gigix 写道 zkj_beyond 写道 脚本语言可以写出十分灵活的代码。可它比较难懂
通常不会比Java程序更难懂,我觉得 引用 <script>
var str = "I had a ((gem:an adjective)) sandwich for lunch today. It dripped all over my ((gem)) and ((a noun)). "; /**** Start ****/ var h = {};// it's a Hash document.write(str.replace(/\(\(([^)]+)\)\)/ig,function($1,$2){ var k = $2.split(":")[0],o=$2.split(":")[1]||k; return "<b style='color:red'>"+ (h[k]||(h[k]=prompt("Give me "+o,"")))+"</b>"; })); </script> ruby我还没开始,就javascript代码。 1、在javascript中把函数当成参数传递,确实比较难懂。 2、按照马叔的重构里说,尽量用小函数代替那些复杂的代码。 3、象以上代码如果我是 var str = "I had a ((gem:an adje:cti:ve)) sandwich for lunch today. It dripped all over my ((gem)) and ((a noun)). "; |
|
返回顶楼 | |
发表时间:2006-04-14
Trustno1 写道 potian 写道 cookoo 写道 Trustno1 写道 @timeout = options["timeout"] || DEFAULT_TIMEOUT
按我这个行业的习惯,这样写真的很成问题.一来||的左右求值序到底是那种并不确定,依赖于语言和编译器解释器的实现.第二,如果 options["timeout"] 如果是一个函数运算,这个函数是不是执行依赖于||另外一端的求值以及编译器是不是进行截断求值,非常的可怕的写法. 在c是个问题, 在ruby不是问题, 呵呵. c 有问题吗,10多年用下来好像还是第1次听说 比如说这种代码把 bool c=a==true||do_something()==false; 这种代码就是二义性的.do_something到底是不是执行,仰赖于a的取值.你不能保证在有side effection的情况下,a的求值总是满足do_something的调用条件. 这种两义性确实可能造成不可读性,但是这是你写成这样的,早期的C程序里面确实有人把这种东西用到极端,一个循环只有一个条件等等的情况,但合理地运用这种副作用也是C的一个习惯用语.任何东西都是一个度的问题, 引用 而且在某些安全性的情况下,比如说我通过内存溢出的漏洞,覆盖a的值,那么就能控制do_something的执行.这是一种非常危险的写法. C是弱类型的,Ruby是强类型的,但这和可读性问题不大 引用 所以我的倾向是,||,&&只用于bool型变量的运算,而不要带任何函数返回值的运算. 度的问题,前面我写的话可以读成 超时等于传入的参数,否则使用缺省值,否则.... |
|
返回顶楼 | |
发表时间:2006-04-14
zkj_beyond 写道 gigix 写道 zkj_beyond 写道 脚本语言可以写出十分灵活的代码。可它比较难懂
通常不会比Java程序更难懂,我觉得 引用 <script>
var str = "I had a ((gem:an adjective)) sandwich for lunch today. It dripped all over my ((gem)) and ((a noun)). "; /**** Start ****/ var h = {};// it's a Hash document.write(str.replace(/\(\(([^)]+)\)\)/ig,function($1,$2){ var k = $2.split(":")[0],o=$2.split(":")[1]||k; return "<b style='color:red'>"+ (h[k]||(h[k]=prompt("Give me "+o,"")))+"</b>"; })); </script> ruby我还没开始,就javascript代码。 1、在javascript中把函数当成参数传递,确实比较难懂。 2、按照马叔的重构里说,尽量用小函数代替那些复杂的代码。 3、象以上代码如果我是 var str = "I had a ((gem:an adje:cti:ve)) sandwich for lunch today. It dripped all over my ((gem)) and ((a noun)). "; 我已经说了,这个例子的可读性不好,但是就这个例子,Ruby的Block也体现出好处了. Ruby和其它脚本语言的区别之一,特别是Perl和PHP,在于它继承了很多Smalltalk里面"正统"的东西,它从一开始就是把自己的目标定义为一种完全的面向对象语言,提供给程序员最自然的表达方式 |
|
返回顶楼 | |
发表时间:2006-04-14
引用 我已经说了,这个例子的可读性不好,但是就这个例子,Ruby的Block也体现出好处了.
Ruby和其它脚本语言的区别之一,特别是Perl和PHP,在于它继承了很多Smalltalk里面"正统"的东西,它从一开始就是把自己的目标定义为一种完全的面向对象语言,提供给程序员最自然的表达方式 先自打一大板。 昨天看了这个贴子后我就下载了ruby。 |
|
返回顶楼 | |
发表时间:2006-04-14
potian 写道 1. 不管是用Ruby写还是用Java写,良好的编程和阅读习惯都不需要指明类型,因为上下文已经说得很清楚了,如果你这样去阅读代码,恐怕一天读不了几句话.代码可理解性的关键在于明确表达你的逻辑和计算意图,匈牙利命名法在这一点上是有害的,你必须首先把变量中的类型部分去掉,才能开始阅读真正的代码含义.最可读的代码是最接近自然语言,不包含缩写(或者只用众所周知的缩写)
问题是,如果不需要上下文就可以了解清楚的事情,就没必要劳烦上下文了,所谓求人不如求己。 否则,还要取决于DEFALUT_TIMEOUT离这个语句的语法距离。按照惯例,不会太远,也不会太近,取决于团队对于常量声明位置的约定。 前面说过,阅读代码至少有两种情形,一种是为了理解代码,另一种是在出错的时候查找问题甚至有时候还要修改代码。如果仅仅为了理解,那么我同意你说的 引用 代码可理解性的关键在于明确表达你的逻辑和计算意图 但是,如果是为了查错,那么,不仅仅需要看明白这段代码想干什么,还要整明白代码是不是正确的干了它想干的事情。 引用 2. 你恐怕搞错了动态和强弱类型之间的区别 Ruby虽然是动态语言,但它却是强类型的,它当然知道这是一个Hash. 我必须承认,这是一个错误。把ruby和其它的一些动态语言搞混了。在一些语言里面,允许使用object['propertyName']的方式来访问属性。因为这个方式有它固有的方便性,所以我直接默认为ruby也有这个特性(应该没有?) 但这个和强弱类型没关系,只是运算符重载而已。 而且,动态强类型只是在赋值以后有意义,赋值阶段意义并不大。 就这个@timeout而言,在这个语句上你是看不出它的类型的。因为不知道options["timeout"]返回的是一个字符串,一个整数,还是其它什么的。只要返回的不是null,那@timeout的类型就是返回值的类型,否则,等于DEFAULT_TIMEOUT的类型。 通过这条语句,阅读者知道编写者想要表达的是@timeout的类型等同于DEFAULT_TIMEOUT的类型,但编写者是不是做到了这一点,必须看到过options['timeout']的赋值才能确定。 所以,如果仅仅为了理解意图,我认为看到这条语句就可以了。但是如果为了查错,那这条语句表述的信息是不充分的。 引用 关于副作用,我不懂什么意思,这是写代码的人决定的,有时侯确实需要利用副作用,这和可读性有什么关系. OO里面副作用的定义感觉有点含糊,应该说是弱化了。 按说有副作用不是问题,只要把方法的目标明确的定义为产生副作用。但是,如果把这类函数放到条件子句里面,就会有问题,因为这个时候返回bool值是主要目的,其副作用很容易被代码阅读者忽略掉。而且,因为可能被短路,也会带来理解上的麻烦。 引用 你讲的对称性我也不理解
其实T1表述的意思比我更加严厉一点,我的倾向是逻辑运算符||/&&两边只能使用boolean型的变量,或者返回boolean变量的只读函数。 所谓对称性我的理解是在一个运算符左右不要出现不同类型的变量。否则,或者用到了语言的自动转型能力,这个时候就在考察阅读者的转型判断力,或者用到了另一些特性(比如这里的逻辑操作符把非null的当做true的处理)。实际上,ruby对于false的定义在这里帮了很大的忙,否则这个赋值语句问题就大了。 总的来说,我们对可读性的理解应该有出入。我的看法是可读性和代码长短并没有必然的关系(对单个函数而言),关键是不要在代码中使用一些隐含的东西或技巧。把该说的东西,用明确而又普通朴实的方式说出来,那可读性就强一些。当然,会很罗嗦。 或者,把阅读者当做语言的入门者。 |
|
返回顶楼 | |
发表时间:2006-04-14
举个例子,从可读性的角度来说,下面的代码(假设max为奇数,否则更加没法比)
int sum=0; for(int i=1;i<=max;i++);{ sum += i; } 肯定比 int sum = (1+max);/2 * max 要强。 当然,有时候为了效率,是需要牺牲可读性的。但是,是不是需要为了简洁而牺牲可读性呢? |
|
返回顶楼 | |
发表时间:2006-04-14
长短肯定是一个问题,但不是最重要的,我对可读性的理解很简单,就是最好按程序读下去就理解了
上面的代码不仅仅是在可读性上的差别,从语言翻译的角度来说,他们并不是等价性的,当然第一种在可读性上更好.(奇数偶数倒是没什么关系) 当然语言的熟悉是必须的,对C可读性好的写法,对Java不一定是可读的,每种语言都有它的习惯用语,我们是建立在对两种语言熟悉程度差不多的情况下,阅读代码的难易程度,譬如上面的代码,在ruby中写成 (1..max);.inject { |sum, i| sum+i} 如果熟悉Ruby(或者smalltalk等等)就会读成从1到max,每个整数依此累加, 如果不熟悉,那就变成天书了. |
|
返回顶楼 | |
发表时间:2006-04-14
引用 上面的代码不仅仅是在可读性上的差别,从语言翻译的角度来说,他们并不是等价性的,当然第一种在可读性上更好.(奇数偶数倒是没什么关系) 那个式子有问题,所以导致奇偶数有关系,写成这样就没关系了: int sum = (1+max); * max / 2 前面那个属于思维短路了。没去想交换律, 引用 当然语言的熟悉是必须的,对C可读性好的写法,对Java不一定是可读的,每种语言都有它的习惯用语,我们是建立在对两种语言熟悉程度差不多的情况下 应该说我们的最主要差异就在这里了,代码的编写者/评审者一般容易精通代码所使用的语言,但是阅读者很难说了。所以编写者的代码水平应当向预计的阅读者看齐。 或者说,最佳情况能够让菜鸟级的水平(刚入门的那种)看明白。这样,就可以让一个成本稍低的团队去维护一个成熟的分支代码库。 |
|
返回顶楼 | |