前情提要:
关于异常的所谓 path 。
所谓 happy path 的问题,我倒是得补充一个观点:排除上层的业务相关的合理性,在分析一般语言设计和程序的惯用法时,跟强调所谓的 control flow 一样,这是“静态分析本位”。
Control flow 的问题在于片面强调源代码的静态结构,而忽视了 control effect 是不论哪个翻译和执行阶段都普遍存在的事实。在这种思路的指导下,以静态分析确定“排除 unhappy ”作为优化 control 的分析变换的第一要务。这本来只应该是实现细节,却变成了影响程序表示的全局因素,加重 intraprocedural 和 interprocedural 变换的区别影响优化翻译器的整体结构,放弃更多的优化机会,实在可笑。
片面强调 happy path 同等的逻辑上同样是荒谬的。对一个典型的静态语言来讲,运行时根本看不到完整的源代码信息,于是如果 happy 是源代码结构单方面决定的,是不是 happy 根本对运行时无关紧要。对运行时有差别的,是有没有用到特定的控制关键字以使运行时能够排除(然后扣上不 happy 的帽子当作不存在),所以 happy 的地位实际只是一个相当于一个 [[likely]] 而已;具体形态上,指派什么叫 happy 的原则使之更像顺序分支不写 [[likely]] 而遵循字面顺序来表示命中频度次序。
说这是“静态分析本位”,是因为如果放弃可静态分析源代码取得结构差异这个前提,是不是 happy path 几乎是无法确定的——即便实现普遍有偏好,跟隐含 [[likely]] 一样,这也是源代码构造本身受到的限制:不得不有差异性。即便如此,指派什么算 happy 的方法比 [[likely]] 仍然更加无理:如果源代码默认自上而下扫描所以先扫描到的构造先被代码生成这点在纠结省 pass 的角度上还有那么点合理性,有和没有异常哪个是 happy 都是说得通的。
而且,凭什么(包括隐式的 [[likely]] 的实际效果就不应该被依赖,而 happy path 和 unhappy path 的区别就更该被依赖呢?这种情况下,强调 happy path 只是因为某些人惧怕特定的 control operator 而已——具体来说,这里是 throw 和 catch 。如果这些人理智一点,应该同样惧怕 if 才对,但实际上这里并没这回事。那么这种对 try 和 if 的双标又是为何呢?
(严格来说,其实确有没有底气依赖 if 分支性能又没可移植的手段来解决问题而只能被迫接受的窝囊用户,但这些用户用几乎所有高级语言都会遇到这种问题,被这里涉及的其他所有人鄙视,因此不需要继续讨论了。)
分析背后的原因,恐怕是跟把异常实现做得烂的根本原因是一样的。这些目光短浅没有计算模型理论常识的用户,不知道 control effect 和 mutable state 一样在计算系统中的普遍存在性,虽然他们很奇怪地仍然在不限范围的通用计算中(被迫?)接受了分支(if) 这个例外。而在一般体系结构智商,他们至少还必须接受返回(return) 这样更多的例外。这些例外都相当地弱小,乃至甚至不能组合(而能替代异常),因为是特例也不能简化到一般意义的程序分析到哪去。也正是这种假定“try 不像 if 和 return 所以就不应该在‘正常’程序逻辑出现”的妄断,造就了某些人把异常设计和实现得那么烂,仍能恬不知耻的脸皮。
那么,是什么理由给这种无知撑腰呢?
(要知道 abstract machine 可不依赖指令寄存器这类细节,都不依赖翻译生成代码,就更不用提生成代码的布局了。所以抛开源代码这里也找不到借口。)
除了现存的理由和工具偏好外,这种思潮可能往上追溯到结构化编程运动,也就是 considered HARMFUL 的历史上。很遗憾,当时的理论计算机科学对这方面完全不成气候(虽然现在也没好哪去),所以外行在因为历史局限(当时词法作用域都没怎么流行)的背景下,对某种可行性的描述误认为泛型加以推广了。
不过不管锅是谁的,这种明确因为无知引发的错误必须被纠正。拒不改正,那就和前人无关了。
至于 happy 的合理的地方,也就是用户确实需要表达哪个是 happy 的上层业务的动机,应该引入类似 [[likely]] 的 opt-in 的明确 hint 来解决,而不应依赖表面上是 convention over configuration 实际连 convention 都没有的依赖代码布局或者关键字的位置这样的破罐子破摔。不过阻碍引入自由组合 control operator 来实现这样的解的,恰恰又是那群 try 恐惧症患者。所以,这怕又是很长一段时间内无解的问题了。
而在此之前,那坨把问题搞复杂,把设计和实现搞烂的鸟人,还真不配纠结哪个 happy 不 happy 。
关于异常的所谓 path 。
所谓 happy path 的问题,我倒是得补充一个观点:排除上层的业务相关的合理性,在分析一般语言设计和程序的惯用法时,跟强调所谓的 control flow 一样,这是“静态分析本位”。
Control flow 的问题在于片面强调源代码的静态结构,而忽视了 control effect 是不论哪个翻译和执行阶段都普遍存在的事实。在这种思路的指导下,以静态分析确定“排除 unhappy ”作为优化 control 的分析变换的第一要务。这本来只应该是实现细节,却变成了影响程序表示的全局因素,加重 intraprocedural 和 interprocedural 变换的区别影响优化翻译器的整体结构,放弃更多的优化机会,实在可笑。
片面强调 happy path 同等的逻辑上同样是荒谬的。对一个典型的静态语言来讲,运行时根本看不到完整的源代码信息,于是如果 happy 是源代码结构单方面决定的,是不是 happy 根本对运行时无关紧要。对运行时有差别的,是有没有用到特定的控制关键字以使运行时能够排除(然后扣上不 happy 的帽子当作不存在),所以 happy 的地位实际只是一个相当于一个 [[likely]] 而已;具体形态上,指派什么叫 happy 的原则使之更像顺序分支不写 [[likely]] 而遵循字面顺序来表示命中频度次序。
说这是“静态分析本位”,是因为如果放弃可静态分析源代码取得结构差异这个前提,是不是 happy path 几乎是无法确定的——即便实现普遍有偏好,跟隐含 [[likely]] 一样,这也是源代码构造本身受到的限制:不得不有差异性。即便如此,指派什么算 happy 的方法比 [[likely]] 仍然更加无理:如果源代码默认自上而下扫描所以先扫描到的构造先被代码生成这点在纠结省 pass 的角度上还有那么点合理性,有和没有异常哪个是 happy 都是说得通的。
而且,凭什么(包括隐式的 [[likely]] 的实际效果就不应该被依赖,而 happy path 和 unhappy path 的区别就更该被依赖呢?这种情况下,强调 happy path 只是因为某些人惧怕特定的 control operator 而已——具体来说,这里是 throw 和 catch 。如果这些人理智一点,应该同样惧怕 if 才对,但实际上这里并没这回事。那么这种对 try 和 if 的双标又是为何呢?
(严格来说,其实确有没有底气依赖 if 分支性能又没可移植的手段来解决问题而只能被迫接受的窝囊用户,但这些用户用几乎所有高级语言都会遇到这种问题,被这里涉及的其他所有人鄙视,因此不需要继续讨论了。)
分析背后的原因,恐怕是跟把异常实现做得烂的根本原因是一样的。这些目光短浅没有计算模型理论常识的用户,不知道 control effect 和 mutable state 一样在计算系统中的普遍存在性,虽然他们很奇怪地仍然在不限范围的通用计算中(被迫?)接受了分支(if) 这个例外。而在一般体系结构智商,他们至少还必须接受返回(return) 这样更多的例外。这些例外都相当地弱小,乃至甚至不能组合(而能替代异常),因为是特例也不能简化到一般意义的程序分析到哪去。也正是这种假定“try 不像 if 和 return 所以就不应该在‘正常’程序逻辑出现”的妄断,造就了某些人把异常设计和实现得那么烂,仍能恬不知耻的脸皮。
那么,是什么理由给这种无知撑腰呢?
(要知道 abstract machine 可不依赖指令寄存器这类细节,都不依赖翻译生成代码,就更不用提生成代码的布局了。所以抛开源代码这里也找不到借口。)
除了现存的理由和工具偏好外,这种思潮可能往上追溯到结构化编程运动,也就是 considered HARMFUL 的历史上。很遗憾,当时的理论计算机科学对这方面完全不成气候(虽然现在也没好哪去),所以外行在因为历史局限(当时词法作用域都没怎么流行)的背景下,对某种可行性的描述误认为泛型加以推广了。
不过不管锅是谁的,这种明确因为无知引发的错误必须被纠正。拒不改正,那就和前人无关了。
至于 happy 的合理的地方,也就是用户确实需要表达哪个是 happy 的上层业务的动机,应该引入类似 [[likely]] 的 opt-in 的明确 hint 来解决,而不应依赖表面上是 convention over configuration 实际连 convention 都没有的依赖代码布局或者关键字的位置这样的破罐子破摔。不过阻碍引入自由组合 control operator 来实现这样的解的,恰恰又是那群 try 恐惧症患者。所以,这怕又是很长一段时间内无解的问题了。
而在此之前,那坨把问题搞复杂,把设计和实现搞烂的鸟人,还真不配纠结哪个 happy 不 happy 。