有好几次,当我想起来的时候,总是会问自己:我为什么要放弃 Go 语言?这个决定是正确的吗?是明智和理性的吗?其实我一直在认真思考这个问题。
开门见山地说,我当初放弃 Go 语言( golang ),就是因为两个“不爽”:第一,对 Go 语言本身不爽;第二,对 Go 语言社区里的某些人不爽。毫无疑问,这是非常主观的结论。但是我有足够详实的客观的论据,用以支撑这个看似主观的结论。
第-1 节:更新日志(倒叙) Liigo 2021-07-13 补记 14:今日 HN 热帖上大伙普遍吐槽 channel ,要用好真的很难。judofyr: "Channels are extremely subtle in my experience". laumars: "It took me a loooong time to fully wrap my head around channels. They’re definitely not explicit and full of subtle yet devastating bugs when used inappropriately (which is all to easy to do too)." 💡 另将本文更新日志从文末移至文首作为第-1 节,并改为按日期倒叙排列。
Liigo 2020-2-19 补记 13:本文末尾增加 Golang 2.0 泛型相关信息。
Liigo 2016-5-15 补记 12:文中第 2 节(我为什么对 Go 社区的人不爽)增加 netroby 和 D 语言联合创始人的现身说法。补充说明 Go 1.5 后不再使用 C 语言开发。
Liigo 2016-3-3 补记 11:文中 1.5 节(垃圾回收器/GC )末尾增加一段,再次提示开发者重视 Go 语言 GC 的潜在问题。
Liigo 2015-7-17 补记 10:文中 1.11 节(泛型)增加来自 HN 的延伸阅读链接,开发者们抱怨 Go 欠缺泛型支持。
Liigo 2015-7-3 补记 9:文中 1.5 节(垃圾回收器/GC )增加 “Stop the world” 相关的三个链接。
Liigo 2015-7-2 补记 8:前两天网上出现了一篇本文的驳文,《驳狗屎文 "我为什么放弃 Go 语言"》,作者是 chai2010 ,请读者们参照阅读,顺便领略一下本文后半部分描述过的 Go 粉的"风采"。(这篇驳文至少有两个好处:1 它全文引用了本文(便于读者参照); 2 使用了本文当时的最新版(包含了补记 7)。)
Liigo 2015-6-2 补记 7:补充两篇英文:Why Go Is Not Good (作者 Will Yager 重点批评了 Go 语言的设计不佳甚至是倒退),Leaving Go (作者 Danny Gratzer 放弃 Go 语言的原因主要是:没有泛型,充满黑魔法)。这两篇文章都是针对具体问题做具体分析的,与本文写作精神一致,务实不务虚。其中提到的对 Go 语言不满的地方,本文也多有涉及,结论类似。
Liigo 2015-5-29 补记 6:补充说明 Go 语言直到 2015 年下半年 1.5 发布后才将 GOMAXPROCS 设置为大于 1 的默认值(HN),他们文中承认之前一直默认设置为 1 是因为调度器不完善(与我此文最初发表时的猜测一致)。
Liigo 2015-4-1 补记 5:文中 1.10 (黑魔法)和 1.12 (接口)章节增加了两处“延伸阅读”链接,被引用的链接后面均有大量网友评论。此举主要是为了说明本文观点并非一家之言。
Liigo 2015-1-31 补记 4:全世界认为 Go 语言不好的可不只是我 Liigo 一个人。国外著名的问答网站 Quora 上面有个人气很高的提问,“为什么不要用 Go 语言”(英文网页),看看那排名最前的两个答案,以及广大程序员们给这两个答案的数百个“赞”,都足以说明 Go 语言自身的问题是客观存在的。人民群众的眼睛是雪亮的。
Liigo 2014-4-29 补记 3:Go 语言的拥护者们,似乎连 Go 语言的“核心优势”都说不出几条。知乎上很有人气的一条问答《为什么要使用 Go 语言,Go 语言的优势在哪里》,连静态编译、GC 、跨平台都拿出来说了(无视 C/C++/Java ),甚至连简单易学(无视 Python/易语言)、“丰富的”标准库(跟谁比?敢跟 Java/C#/Python 比么?)、好用的工具链( gofmt )都扯出来了,可见除了“并发、网络”之外,他们也讲不出另外的什么核心优势了,只能靠一些周边的东西凑数。
Liigo 2014-4-29 补记 2:著名的编程语言研究专家王垠写了一篇《对 Go 语言的综合评价》(晚于本博文发表约三五天),也是总体上持批判态度,看衰 Go 语言。读者们可以对照阅读。
Liigo 2014-4-29 补记 1:Go 语言社区还有一个很奇特的现象,就是中国社区独大,国外社区要小的多。有外国网友还专门写了一篇文章研究《为什么 Golang 中国社区独大》这个问题(文中也提到了我这篇博文)。通常来说,在 IT 和软件领域,向来都是国外先进国家引领技术潮流,然后国内缓慢跟进。而到了 Go 语言这里,恰恰反过来了,似乎暗示着在国外的主流软件开发技术人员并不怎么待见 Go 语言,Go 只是在国内受到一帮人的盲目推崇而已,至于这帮人的眼光如何,反正我不看好。
第 0 节:我的 Go 语言经历 先说说我的经历吧,以避免被无缘无故地当作 Go 语言的低级黑。
2009 年底,Go 语言( golang )第一个公开版本发布,笼罩着“Google 公司制造”的光环,吸引了许多慕名而来的尝鲜者,我( Liigo )也身居其中,笼统的看了一些 Go 语言的资料,学习了基础的教程,因对其语法中的分号和花括号不满,很快就遗忘掉了,没拿它当一回事。
两年之后,2011 年底,Go 语言发布 1.0 的计划被提上日程,相关的报道又多起来,我再次关注它,重新评估之后决定深入参与 Go 语言。我订阅了其 users 、nuts 、dev 、commits 等官方邮件组,坚持每天阅读其中的电子邮件,以及开发者提交的每一次源代码更新,给 Go 提交了许多改进意见,甚至包括修改 Go 语言编译器源代码直接参与开发任务。如此持续了数月时间。
到 2012 年初,Go 1.0 发布,语言和标准库都已经基本定型,不可能再有大幅改进,我对 Go 语言未能在 1.0 定型之前更上一个台阶、实现自我突破,甚至带着诸多明显缺陷走向 1.0 ,感到非常失望,因而逐渐疏远了它(所以 Go 1.0 之后的事情我很少关心)。后来看到即将发布的 Go 1.1 的 Release Note ,发现语言层面没有太大改变,只是在库和工具层面有所修补和改进,感到它尚在幼年就失去成长的动力,越发失望。外加 Go 语言社区里的某些人,其中也包括 Google 公司负责开发 Go 语言的某些人,其态度、言行,让我极度厌恶,促使我决绝地离弃 Go 语言。
在上一个 10 年,我( Liigo )在我所属的公司里,深度参与了两个编程语言项目的开发。我想,对于如何判断某个编程语言的优劣,或者说至少对于如何判断某个编程语言是否适合于我自己,我应该还是有一点发言权的。
第 1 节:我为什么对 Go 语言不爽? Go 语言有很多让我不爽之处,这里列出我现在还能记起的其中一部分,排名基本上不分先后。读者们耐心地看完之后,还能淡定地说一句“我不在乎”吗?
1.1 不允许左花括号另起一行 关于对花括号的摆放,在 C 语言、C++、Java 、C#等社区中,十余年来存在持续争议,从未形成一致意见。在我看来,这本来就是主观倾向很重的抉择,不违反原则不涉及是非的情况下,不应该搞一刀切,让程序员或团队自己选择就足够了。编程语言本身强行限制,把自己的喜好强加给别人,得不偿失。无论倾向于其中任意一种,必然得罪与其对立的一群人。虽然我现在已经习惯了把左花括号放在行尾,但一想到被禁止其他选择,就感到十分不爽。Go 语言这这个问题上,没有做到“团结一切可以团结的力量”不说,还有意给自己树敌,太失败了。
1.2 编译器莫名其妙地给行尾加上分号 对 Go 语言本身而言,行尾的分号是可以省略的。但是在其编译器( gc )的实现中,为了方便编译器开发者,却在词法分析阶段强行添加了行尾的分号,反过来又影响到语言规范,对“怎样添加分号”做出特殊规定。这种变态做法前无古人。在左花括号被意外放到下一行行首的情况下,它自动在上一行行尾添加的分号,会导致莫名其妙的编译错误( Go 1.0 之前),连它自己都解释不明白。如果实在处理不好分号,干脆不要省略分号得了;或者,Scala 和 JavaScript 的编译器是开源的,跟它们学学怎么处理省略行尾分号可以吗?
1.3 极度强调编译速度,不惜放弃本应提供的功能 程序员是人不是神,编码过程中免不了因为大意或疏忽犯一些错。其中有一些,是大家集体性的很容易就中招的错误( Go 语言里的例子我暂时想不起来,C++里的例子有“基类析构函数不是虚函数”)。这时候编译器应该站出来,多做一些检查、约束、核对性工作,尽量阻止常规错误的发生,尽量不让有潜在错误的代码编译通过,必要时给出一些警告或提示,让程序员留意。编译器不就是机器么,不就是应该多做脏活累活杂活、减少人的心智负担么?编译器多做一项检查,可能会避免数十万程序员今后多年内无数次犯同样的错误,节省的时间不计其数,这是功德无量的好事。但是 Go 编译器的作者们可不这么想,他们不愿意自己多花几个小时给编译器增加新功能,觉得那是亏本,反而减慢了编译速度。他们以影响编译速度为由,拒绝了很多对编译器改进的要求。典型的因噎废食。强调编译速度固然值得赞赏,但如果因此放弃应有的功能,我不赞成。
1.4 错误处理机制太原始 在 Go 语言中处理错误的基本模式是:函数通常返回多个值,其中最后一个值是 error 类型,用于表示错误类型极其描述;调用者每次调用完一个函数,都需要检查这个 error 并进行相应的错误处理:if err != nil { /这种代码写多了不想吐么/ }。此模式跟 C 语言那种很原始的错误处理相比如出一辙,并无实质性改进。实际应用中很容易形成多层嵌套的 if else 语句,可以想一想这个编码场景:先判断文件是否存在,如果存在则打开文件,如果打开成功则读取文件,如果读取成功再写入一段数据,最后关闭文件,别忘了还要处理每一步骤中出现错误的情况,这代码写出来得有多变态、多丑陋?实践中普遍的做法是,判断操作出错后提前 return ,以避免多层花括号嵌套,但这么做的后果是,许多错误处理代码被放在前面突出的位置,常规的处理逻辑反而被掩埋到后面去了,代码可读性极差。而且,error 对象的标准接口只能返回一个错误文本,有时候调用者为了区分不同的错误类型,甚至需要解析该文本。除此之外,你只能手工强制转换 error 类型到特定子类型(静态类型的优势没了)。至于 panic - recover 机制,致命的缺陷是不能跨越库的边界使用,注定是一个半成品,最多只能在自己的 pkg 里面玩一玩。Java 的异常处理虽然也有自身的问题(比如 Checked Exceptions ),但总体上还是比 Go 的错误处理高明很多。
1.5 垃圾回收器( GC )不完善、有重大缺陷 在 Go 1.0 前夕,其垃圾回收器在 32 位环境下有内存泄漏,一直拖着不肯改进,这且不说。Go 语言垃圾回收器真正致命的缺陷是,会导致整个进程不可预知的间歇性停顿( Stop the World )。像某些大型后台服务程序,如游戏服务器、APP 容器等,由于占用内存巨大,其内存对象数量极多,GC 完成一次回收周期,可能需要数秒甚至更长时间,这段时间内,整个服务进程是阻塞的、停顿的,在外界看来就是服务中断、无响应,再牛逼的并发机制到了这里统统失效。垃圾回收器定期启动,每次启动就导致短暂的服务中断,这样下去,还有人敢用吗?这可是后台服务器进程,是 Go 语言的重点应用领域。以上现象可不是我假设出来的,而是事实存在的现实问题,受其严重困扰的也不是一家两家了( 2013 年底 ECUG Con 2013 ,京东的刘奇提到了 Go 语言的 GC 、defer 、标准库实现是性能杀手,最大的痛苦是 GC ;美团的沈锋也提到 Go 语言的 GC 导致后台服务间隔性停顿是最大的问题。更早的网络游戏仙侠道开发团队也曾受 Go 垃圾回收的沉重打击)。在实践中,你必须努力减少进程中的对象数量,以便把 GC 导致的间歇性停顿控制在可接受范围内。除此之外你别无选择(难道你还想自己更换 GC 算法、甚至砍掉 GC ?那还是 Go 语言吗?)。跳出圈外,我近期一直在思考,一定需要垃圾回收器吗?没有垃圾回收器就一定是历史的倒退吗?(可能会新写一篇博客文章专题探讨。)
2016 年 3 月 3 日 Liigo 补记:直到 2015 年底,Go 1.5 新 GC 发布后数月,仍获知有大陆圈内知名团队因为 GC 的原因考虑换掉 Go 语言,颇有感触。当软件系统逐步发展到更庞大更复杂的时候,Go 语言的垃圾回收器(GC)就变成了指不定啥时候会出现的拦路虎,让人进退两难。进,暂时没有确切有效的技术手段对付响应延迟和内存暴涨;退,多年开发付出的心血付之东流损失惨重。语言选型之前多做调查分析,如果一定要用 Go 语言开发,控制系统规模和复杂度,避开底层的核心业务,可能是比较明智的选择。
1.6 禁止未使用变量和多余 import
Go 编译器不允许存在被未被使用的变量和多余的 import ,如果存在,必然导致编译错误。但是现实情况是,在代码编写、重构、调试过程中,例如,临时性的注释掉一行代码,很容易就会导致同时出现未使用的变量和多余的 import ,直接编译错误了,你必须相应的把变量定义注释掉,再翻页回到文件首部把多余的 import 也注释掉,……等事情办完了,想把刚才注释的代码找回来,又要好几个麻烦的步骤。还有一个让人蛋疼的问题,编写数据库相关的代码时,如果你 import 某数据库驱动的 pkg ,它编译给你报错,说不需要 import 这个未被使用的 pkg ;但如果你听信编译器的话删掉该 import ,编译是通过了,运行时必然报错,说找不到数据库驱动;你看看程序员被折腾的两边不是人,最后不得不请出大神:import _
。对待这种问题,一个比较好的解决方案是,视其为编译警告而非编译错误。但是 Go 语言开发者很固执,不容许这种折中方案。
1.7 创建对象的方式太多令人纠结 创建对象的方式,调用 new 函数、调用 make 函数、调用 New 方法、使用花括号语法直接初始化结构体,你选哪一种?不好选择,因为没有一个固定的模式。从实践中看,如果要创建一个语言内置类型(如 channel 、map )的对象,通常用 make 函数创建;如果要创建标准库或第三方库定义的类型的对象,首先要去文档里找一下有没有 New 方法,如果有就最好调用 New 方法创建对象,如果没有 New 方法,则退而求其次,用初始化结构体的方式创建其对象。这个过程颇为周折,不像 C++、Java 、C#那样直接 new 就行了。
1.8 对象没有构造函数和析构函数 没有构造函数还好说,毕竟还有自定义的 New 方法,大致也算是构造函数了。没有析构函数就比较难受了,没法实现 RAII 。额外的人工处理资源清理工作,无疑加重了程序员的心智负担。没人性啊,还嫌我们程序员加班还少吗? C++里有析构函数,Java 里虽然没有析构函数但是有人家 finally 语句啊,Go 呢,什么都没有。没错,你有个 defer ,可是那个 defer 问题更大,详见下文吧。
1.9 defer 语句的语义设定不甚合理 Go 语言设计 defer 语句的出发点是好的,把释放资源的“代码”放在靠近创建资源的地方,但把释放资源的“动作”推迟( defer )到函数返回前执行。遗憾的是其执行时机的设置似乎有些不甚合理。设想有一个需要长期运行的函数,其中有无限循环语句,在循环体内不断的创建资源(或分配内存),并用 defer 语句确保释放。由于函数一直运行没有返回,所有 defer 语句都得不到执行,循环过程中创建的大量短暂性资源一直积累着,得不到回收。而且,系统为了存储 defer 列表还要额外占用资源,也是持续增加的。这样下去,过不了多久,整个系统就要因为资源耗尽而崩溃。像这类长期运行的函数,http.ListenAndServe()就是典型的例子。在 Go 语言重点应用领域,可以说几乎每一个后台服务程序都必然有这么一类函数,往往还都是程序的核心部分。如果程序员不小心在这些函数中使用了 defer 语句,可以说后患无穷。如果语言设计者把 defer 的语义设定为在所属代码块结束时(而非函数返回时)执行,是不是更好一点呢?可是 Go 1.0 早已发布定型,为了保持向后兼容性,已经不可能改变了。小心使用 defer 语句!一不小心就中招。
1.10 许多语言内置设施不支持用户定义的类型 for in 、make 、range 、channel 、map 等都仅支持语言内置类型,不支持用户定义的类型(?)。用户定义的类型没法支持 for in 循环,用户不能编写像 make 、range 那样“参数类型和个数”甚至“返回值类型和个数”都可变的函数,不能编写像 channel 、map 那样类似泛型的数据类型。语言内置的那些东西,处处充斥着斧凿的痕迹。这体现了语言设计的局限性、封闭性、不完善,可扩展性差,像是新手作品——且不论其设计者和实现者如何权威。延伸阅读:Go 语言是 30 年前的陈旧设计思想,用户定义的东西几乎都是二等公民( Tikhon Jelvis )。
1.11 没有泛型支持,常见数据类型接口丑陋 没有泛型的话,List 、Set 、Tree 这些常见的基础性数据类型的接口就只能很丑陋:放进去的对象是一个具体的类型,取出来之后成了无类型的 interface{}(可以视为所有类型的基础类型),还得强制类型转换之后才能继续使用,令人无语。Go 语言缺少 min 、max 这类函数,求数值绝对值的函数 abs 只接收/返回双精度小数类型,排序接口只能借助 sort.Interface 无奈的回避了被比较对象的类型,等等等等,都是没有泛型导致的结果。没有泛型,接口很难优雅起来。Go 开发者没有明确拒绝泛型,只是说还没有找到很好的方法实现泛型(能不能学学已经开源的语言呀)。现实是,Go 1.0 已经定型,泛型还没有,那些丑陋的接口为了保持向后兼容必须长期存在着。延伸阅读:HN 网友抱怨 Go 没有泛型。
1.12 实现接口不需要明确声明 这一条通常是被当作 Go 语言的优点来宣传的。但是也有人不赞同,比如我。如果一个类型用 Go 语言的方式默默的实现了某个接口,使用者和代码维护者都很难发现这一点(除非仔细核对该类型的每一个方法的函数签名,并跟所有可能的接口定义相互对照),自然也想不到与该接口有关的应用,显得十分隐晦,不直观。支持者可能会辩解说,我可以在文档中注明它实现了哪些接口。问题是,写在文档中,还不如直接写到类型定义上呢,至少还能得到编译器的静态类型检查。缺少了编译器的支持,当接口类型的函数签名被改变时,当实现该接口的类型方法被无意中改变时,实现者可能很难意识到,该类型实现该接口的隐含约束事实上已经被打破了。又有人辩解说,我可以通过单元测试确保类型正确实现了接口呀。我想说的是,明明可以通过明确声明实现接口,享受编译器提供的类型检查,你却要自己找麻烦,去写原本多余的单元测试,找虐很爽吗? Go 语言的这种做法,除了减少一些对接口所在库的依赖之外,没有其他好处,得不偿失。延伸阅读:为什么我不喜欢 Go 语言式的接口(老赵)。
1.13 省掉小括号却省不掉花括号 Go 语言里面的 if 语句,其条件表达式不需要用小括号扩起来,这被作为“代码比较简洁”的证据来宣传。可是,你省掉了小括号,却不能省掉大括号啊,一条完整的 if 语句至少还得三行吧,人家 C 、C++、Java 都可以在一行之内搞定的(可以省掉花括号)。人家还有 x?a:b 表达式呢,也是一行搞定,你 Go 语言用 if else 写至少得五行吧?哪里简洁了?
1.14 编译生成的可执行文件尺寸非常大 记得当年我写了一个很简单的程序,把所有系统环境变量的名称和值输出到控制台,核心代码也就那么三五行,结果编译出来把我吓坏了:EXE 文件的大小超过 4MB 。如果是 C 语言写的同样功能的程序,0.04MB 都是多的。我把这个信息反馈到官方社区,结果人家不在乎。是,我知道现在的硬盘容量都数百 GB 、上 TB 了……可您这种优化程度……怎么让我相信您在其他地方也能做到不错呢。(再次强调一遍,我所有的经验和数据都来自 Go 1.0 发布前夕。)
1.15 不支持动态加载类库 静态编译的程序当然是很好的,没有额外的运行时依赖,部署时很方便。但是之前我们说了,静态编译的文件尺寸很大。如果一个软件系统由多个可执行程序构成,累加起来就很可观。如果用动态编译,发布时带同一套动态库,可以节省很多容量。更关键的是,动态库可以运行时加载和卸载,这是静态库做不到的。还有那些 LGPL 等协议的第三方 C 库受版权限制是不允许静态编译的。至于动态库的版本管理难题,可以通过给动态库内的所有符号添加版本号解决。无论如何,应该给予程序员选择权,让他们自己决定使用静态库还是动态库。一刀切的拒绝动态编译是不合适的。
1.16 其他 不支持方法和函数重载( overload ) 导入 pkg 的 import 语句后边部分竟然是文本( import ”fmt”) 没有 enum 类型,全局性常量难以分类,iota 把简单的事情复杂化 定义对象方法时,receiver 类型应该选用指针还是非指针让人纠结 定义结构体和接口的语法稍繁,interface XXX{} struct YYY{} 不是更简洁吗?前面加上 type 关键字显得罗嗦。 测试类库 testing 里面没有 AssertEqual 函数,标准库的单元测试代码中充斥着 if a != b { t.Fatal(...) }。 语言太简单,以至于不得不放弃很多有用的特性,“保持语言简单”往往成为拒绝改进的理由。 标准库的实现总体来说不甚理想,其代码质量大概处于“基本可用”的程度,真正到企业级应用领域,往往就会暴露出诸多不足之处。 版本都发展到 1.2 了,goroutine 调度器依旧默认仅使用一个系统线程。GOMAXPROCS 的长期存在似乎暗示着官方从来没有足够的信心,让调度器正确安全地运行在多核环境中。这跟 Go 语言自身以并发为核心的定位有致命的矛盾。(直到 2015 年下半年 1.5 发布后才有改观) 官方发行版中包含了一个叫 oracle 的辅助程序,与 Oracle 数据库毫无关系,却完全无视两者之间的名称混淆。 上面列出的是我目前还能想到的对 Go 语言的不爽之处,毕竟时间过去两年多,还有一些早就遗忘了。其中一部分固然是小不爽,可能忍一忍就过去了,但是很多不爽积累起来,总会时不时地让人难受,时间久了有自虐的感觉。程序员的工作生活本来就够枯燥的,何必呢。
必须要说的是,对于其中大多数不爽之处,我( Liigo )都曾经试图改变过它们:在 Go 1.0 版本发布之前,我在其官方邮件组提过很多意见和建议(甚至包括提交代码 CL ),极力据理力争,可以说付出很大努力,目的就是希望定型后的 Go 语言是一个相对完善的、没有明显缺陷的编程语言。结果是令人失望的,我人微言轻、势单力薄,不可能影响整个语言的发展走向。1.0 之前,最佳的否定自我、超越自我的机会,就这么遗憾地错过了。我最终发现,很多时候不是技术问题,而是技术人员的问题。
第 2 节:我为什么对 Go 语言的某些人不爽? 这里提到的“某些人”主要是两类:一、负责专职开发 Go 语言的 Google 公司员工;二、Go 语言的推崇者和脑残粉丝。我跟这两类人打过很多交道,不胜其烦。再次强调一遍,我指的是“某些”人,而不是所有人,请不要对号入座。
Google 公司内部负责专职开发 Go 语言的核心开发组某些成员,他们倾向于闭门造车,固执己见,对第三方提出的建议不重视。他们常常挂在嘴边的口头禅是:现有的做法很好、不需要那个功能、我们开发 Go 语言是给 Google 自己用的、Google 不需要那个功能、如果你一定要改请 fork 之后自己改、别干提意见请提交代码。很多言行都是“反开源”的。通过一些具体的例子,还能更形象的看清这一层。就留下作为课后作业吧。
我最不能接受的就是他们对 1.0 版本的散漫处理。那时候 Go 还没到 1.0 ,初出茅庐的小学生,有很大的改进空间,是全面翻新的最佳时机,彼时不改更待何时? 1.0 是打地基的版本,基础不牢靠,等 1.0 定型之后,处处受到向后兼容性的牵制,束手缚脚,每前进一步都阻力重重。急于发布 1.0 ,过早定型,留下诸多遗憾,彰显了开发者的功利性强,在技术上不追求尽善尽美。
Go 语言的核心开发成员,他们日常的开发工作是使用 C 语言——Go 语言的编译器和运行时库,包括语言核心数据结构和算法 map 、channel 、scheduler ,都是 C 开发的——真正用自己开发的 Go 语言进行实际的大型应用开发的机会并不多。虽然标准库是用 Go 语言自己写的,但他们却没有大范围使用标准库的经历。实际上,他们缺少使用 Go 语言的实战开发经验,往往不知道处于开发第一线的用户真正需要什么,无法做到设身处地为程序员着想。缺少使用 Go 语言的亲身经历,也意味着他们不能在日常开发中,及时发现和改进 Go 语言的不足。这也是他们往往自我感觉良好的原因。( 2016 年 5 月 15 日补记:2015 年 8 月 Go 1.5 版本之后不再使用 C 语言开发。)
Go 语言社区里,有一大批 Go 语言的推崇者和脑残粉丝,他们满足于现状,不思进取,处处维护心中的“神”,容不得批评意见,不支持对语言的改进要求。当年我对 Go 语言的很多批评和改进意见,极少得到他们的支持,他们不但不支持还给予打击,我就纳闷了,他们难道不希望 Go 语言更完善、更优秀吗?我后来才意识到,他们跟乔帮主的苹果脑残粉丝们,言行一脉相承,具有极端宗教倾向,神化主子、打击异己真是不遗余力呀。简简单单的技术问题,就能被他们上升到意识形态之争。现实的例子是蛮多的,有兴趣的到网上去找吧。正是因为他们的存在,导致更多理智、清醒的 Go 语言用户无法真正融入整个社区。
如果一个项目、团队、社区,到处充斥着赞美、孤芳自赏、自我满足、不思进取,排斥不同意见,拒绝接纳新方案,我想不到它还有什么前进的动力。逆水行舟,是不进反退的。
2016 年 5 月 15 日补记:@netroby:“Golang 社区的神经病和固执,我深有体会。我曾经发过 Issue ,请求 Golang 官方,能为 doc 加上高亮,这样浏览器阅读文档的时候,能快速阅读代码参考。但是被各种拒绝. 他们的理由是很多开发者不喜欢高亮。” https://github.com/golang/go/issues/13178
2016 年 5 月 15 日补记:C++天才人物、D 语言联合创始人 Andrei Alexandrescu:“Go 所走的路线在一些问题上持有极其强硬和死板态度,这些问题有大有小。在比较大的方面,泛型编程被严格控制,甚至贬低到只有"N"个字;有关泛型编程的讨论都是试图去劝阻任何有意义的尝试,这已经足够让人觉得耻辱。从长远来看,技术问题的政治化是一种极其有害的模式,所以希望 Go 社区能够找到修正它的方法。” http://www.csdn.net/article/2015-12-20/2826517
第 3 节:还有比 Go 语言更好的选择吗? 我始终坚持一个颇有辩证法意味的哲学观点:在更好的替代品出现之前,现有的就是最好的。失望是没有用的,抱怨是没有用的,要么接受,要么逃离。我曾经努力尝试过接受 Go 语言,失败之后,注定要逃离。发现更好的替代品之后,无疑加速了逃离过程。还有比 Go 语言更好的替代品吗?当然有。作为一个屌丝程序员,我应该告诉你它是什么,但是我不说。现在还不是时候。我现在不想把这两门编程语言对立起来,引发另一场潜在的语言战争。这不是此文的本意。如果你非要从现有信息中推测它是什么,那完全是你自己的事。如果你原意等,它或许很快会浮出水面,也未可知。
第 4 节:写在最后 我不原意被别人代表,也不愿意代表别人。这篇文章写的是我,一个叫 Liigo 的 80 后屌丝程序员,自己的观点。你完全可以主观地认为它是主观的,也完全可以客观地以为它是客观的,无论如何,那是你的观点。
这篇文字是从记忆里收拾出来的。有些细节虽可考,而不值得考。——我早已逃离,不愿再回到当年的场景。文中涉及的某些细节,可能会因为些许偏差,影响其准确性;也可能会因为缺少出处,影响其客观性。如果有人较真,非要去核实,我相信那些东西应该还在那里。
Go 语言也非上文所述一无是处,它当然有它的优势和特色。读者们判断一件事物,应该是优劣并陈,做综合分析,不能单听我一家负面之言。但是它的那些不爽之处,始终让我不爽,且不能从其优秀处得以完全中和,这是我不得不放弃它的原因。
关于对作者倾向性质疑的声明:
读者看到本文全都是 Go 语言负面性的内容,没有涉及一点 Go 语言好的地方,因而质疑作者的盲目倾向。出现这种结果完全是因为文章主题所限。此前本文末尾也简单提到过,评估一件事物,应当优劣并陈,优势项加分,劣势项减分,做综合评估分析。如果有突出的重大优势,则可以容忍一些较大的劣势;但如果有致命的劣势或多项大劣势,则再大的优势也无法与之中和。中国乒乓球界讲领军人物必须做到“技术全面,特长突出,没有明显弱点”,我甚为赞同。用这句话套用 Go 语言,可以说“技术不全面(人家自己说成简洁),有一点特长(并发),有明显的弱点(包括但不限于本文列出的这些)”。如此一来,优势都被劣势中和了,劣势还是那么突出,自然是得负分,自然是弃用,自然是没有好印象。我在这里可以说观点鲜明、态度明确,不和稀泥。与其看那些盲目推崇 Go 语言的人和文章,笼统的说“好”,不如也顺便看看本文,具体到细节地说“不好”。凡是具体到细节的东西,都是容易证实或证伪的,比笼统的东西(无论是"黑"还是"粉")可信性更高一些。
关于对作者阴谋论的声明:
有某些阴谋论者(例如谢某),说我因一个 Pull Request 被 Go 开发者拒绝而“怀恨至今”,暗示此文是故意报复、抹黑 Go 语言。我对 Golang 有恨吗?当然是有的,那是一个不爽接一个不爽(如本文一一罗列的那些),逐步累积,由量变形成质变的结果,是我对 Golang 综合客观评估之后的主观态度,并非由哪一个单独的事件所主导。要说 Pull Request 被拒绝,Rust 开发者拒绝我的 PR 次数还少吗?比如 https://github.com/mozilla/rust/pull/13014 和 https://github.com/liigo/rust/tree/xp ( https://github.com/rust-lang/rust/issues/12842),要是再算上被拒的 Issues ,那就多的数不清了。我显然不可能因为某些个别的事件,影响到我对某个事物的综合评估(参见前文)。那本文是“故意抹黑”Go 语言吗?我觉得不是,理由有二:1 、这是作者的主观感受,2 、这些感受是以许多客观事实为基础的。如果本文一一列出的那些现象,是不存在的,是虚构出来的,是凭空生成的,那么作者一定是“低级黑”。问题是,那些都是客观存在的事实。把事实说出来,怎么能叫“黑”呢?欢迎读者客观而详细的指正本文中的所有错误。
关于 Golang 2.0 的泛型:
今天( 2020 年 2 月 19 日)看到 HN 的一篇关于 Go2 Generics 的讨论。有网友说到:
Ken Thompson and Rob Pike are mostly out not at all involved with Go anymore. They are 2/3 of the original creators. It’s different people making the decisions now.
我找到如下两个链接基本证实了 Rob Pike 确实已经淡出 Golang 的核心开发组:
golang/go#33892 golang/go#33502 Rob Pike 最近两年仅提交了 4k 行无关紧要的代码; Ken Thompson 就更不用说了,许多年前就已经淡出; Russ Cox 似乎也不太参与 Go2 相关的决策。如此看来,对于 Go2 的泛型而言,非技术方面的障碍已不存在,剩下只是技术性障碍。
Ian Lance Taylor 上周( 2020 年 2 月 13 日)说到:
We're working on it. Some things take time.
1
lance6716 2023-08-18 12:56:30 +08:00 via Android 12
这也太长了。有看完的时间,我又成功拉了几百行的 golang 新鲜💩
|
2
debuggerx 2023-08-18 12:59:41 +08:00 4
个人觉得 go 有 go 的优点和价值,确实有适合它的场景,但是缺点同样明显,所以问题就在于不知道那几年是怎么出现了那么多 go 吹,明明不适合的场景也硬要用,整个跟一邪教似的……
当然现在这种情况好多了,因为新的 rust 邪教已经崛起,相比之下 go 吹倒显得没那么出格了~ |
3
hsfzxjy 2023-08-18 13:02:10 +08:00 via Android
虽然但是,编译是真的快🤣
|
4
deorth 2023-08-18 13:07:54 +08:00 via Android
成见太多,文章太老
|
5
Nazz 2023-08-18 13:12:47 +08:00 via Android 1
太长不看。如果我要放弃 golang ,只会有一个原因,那就是找不到工作。
|
6
chinaguaiu 2023-08-18 13:17:51 +08:00
@debuggerx 不要紧的,Rust 太难了,吹的人有限,很难成席卷之势🤣
|
7
mango88 2023-08-18 13:23:12 +08:00
|
9
dandycheung 2023-08-18 13:33:20 +08:00 via Android
基本可以归类为“村通网”的文章。
|
10
Masoud2023 2023-08-18 13:36:52 +08:00
那就不用
|
12
idealhs 2023-08-18 14:00:05 +08:00
第一次写 Go 的时候他对我一个没用到的 import 报了个错,我就觉得有够逆天
|
13
araraloren 2023-08-18 14:03:39 +08:00 3
@debuggerx 问题的关键是 go 真的没有什么值的吹的
讨厌锈儿,理解锈儿,成为锈儿 |
14
hez2010 2023-08-18 14:04:31 +08:00 1
golang 难道不是从最开始的自我定位就是最适合拉屎的语言?都用 golang 了就不需要管代码到底怎么设计和抽象了,怎么暴力怎么来。
不过也正是因为这样很多一开始根本不会编程的人看到 golang 都能立马上手,甚至比 python 还好上手。他们不需要在入门的时候理解各种语法、概念和工作原理,只要简单理解一下基础类型和控制语句什么的然后照着 api 文档抄就能写出像模像样的东西,算是大力推进了开发者群体下沉吧。 打个比方就是,虽然使用从句能让英语表达更加丰富、信息密度更高、语素重复更少,但不是每个英语学习者都会;而所有英语学习者只要经历了最初的学习就能使用简单句来进行语言表达。 |
15
nullcache 2023-08-18 14:06:04 +08:00
go 感觉抽象能力有点不好,得反射
|
16
kwanzaa 2023-08-18 14:09:10 +08:00
内容过于陈旧,放在今天严重不适合讨论。
|
17
Mexion 2023-08-18 14:17:09 +08:00 1
我觉得这文章已经非常客观了,也确实是 go 存在的比较明显的问题
|
18
Mexion 2023-08-18 14:19:25 +08:00 2
这篇文章中描述的有几点正是我一直不喜欢 go 的原因,虽说我编程至今也就几年,但也接触了几门语言,go 语言是让我最不爽的
|
19
Rooger 2023-08-18 14:29:19 +08:00
你有能力就自己创造一门语言,要么就闭嘴。
|
20
darksword21 2023-08-18 14:30:18 +08:00
能完成我的需求就行,语言什么的无所谓,这么长的关于“语言选择的文章”更是不必浪费时间看
|
21
EAFA0 2023-08-18 14:31:37 +08:00
遍历 map 强制添加随机数 & 一开始不做异常堆栈, 后续又出了个 fmt.Errorf 来打补丁确实让我感受到了设计者的傲慢和妥协, 个人感觉
|
22
justdoit123 2023-08-18 14:36:54 +08:00
@debuggerx 同意。不看场景,拿着锤子找钉子,用起来当然痛苦。我现在看到论坛拼命鼓吹一项新技术,都会有点反感,因为以前也被这样“骗”过。。。
|
23
gaoyangang 2023-08-18 14:52:58 +08:00 via iPhone
内存密集型的服务,go pass
|
24
rrfeng 2023-08-18 14:56:39 +08:00 via Android 5
整体看起来像是:我很牛逼,go (和开发 go 的人)很垃圾,因为那些垃圾人不听我的。
|
25
realNewBee 2023-08-18 15:08:54 +08:00
幸亏先看评论
|
27
ysc3839 2023-08-18 15:17:03 +08:00 via Android 2
|
28
cander0815 2023-08-18 15:18:36 +08:00
@mango88 这是什么 AI 工具?还能上传文件
|
29
wonderfulcxm 2023-08-18 15:18:59 +08:00 via iPhone
如果一个项目、团队、社区,到处充斥着赞美、孤芳自赏、自我满足、不思进取,排斥不同意见,拒绝接纳新方案,我想不到它还有什么前进的动力。逆水行舟,是不进反退的。
我也觉得 go 吹太多了 |
30
Cyshall 2023-08-18 15:25:19 +08:00
我看完了,我个人感觉是比较客观的。
|
31
mango88 2023-08-18 15:29:50 +08:00
@cander0815 claude
|
34
Bazingal 2023-08-18 15:47:02 +08:00
2006-01-02 15:04:05 都有人吹你敢信?
|
35
bequt 2023-08-18 15:53:47 +08:00
看 go 创始人得了,语言需要时间,会完善的。
|
37
sky3hao 2023-08-18 16:15:17 +08:00
用 python 吧, 简单
|
38
TOUJOURSER 2023-08-18 16:19:07 +08:00
本身就是个吃饭的工具搞不懂整天在这上面争论个什么,不喜欢可以挑你喜欢的语言去用就是
|
39
gowk 2023-08-18 16:29:36 +08:00
14 年的文章发上来干嘛?引战?已 B
|
40
zzzkkk 2023-08-18 16:35:33 +08:00
|
41
MoYi123 2023-08-18 16:40:03 +08:00
只要买个 goland, 60%问题都没了.
当然可能写这篇文章的时候还没 goland. |
43
lasuar 2023-08-18 16:57:42 +08:00
加入于 2022-06-05
|
44
gxm44 2023-08-18 17:03:32 +08:00
没有用的语言,才没人喷
|
45
chaleaochexist 2023-08-18 17:05:01 +08:00
最后也没说放弃 go 之后选择了哪门语言
|
46
wei2629 2023-08-18 17:05:04 +08:00
这么说吧。go 在有 gc 的语言中虽然不是 100 分,但是也有 60 分了。你想找一个超过 60 分的,真的还是很困难的。
|
47
chaleaochexist 2023-08-18 17:09:33 +08:00
@mango88 #8 这是怎么做到的 chatgpt 有这个能力嘛?
|
48
tedzhou1221 2023-08-18 17:13:23 +08:00
@chaleaochexist 这个是 claude2
|
49
cnoder 2023-08-18 18:44:00 +08:00 1
if err != nil 真的挺难受的,还好有 copilot
|
50
wheeler 2023-08-18 19:18:25 +08:00 via iPhone
左花括号这种喜好问题都值得拎出来说吗
|
52
vincent7245 2023-08-18 23:01:08 +08:00
有一点还是赞同的:我讨厌 go 语言的脑残粉。
同样也适用于其他语言。 |
53
learningman 2023-08-18 23:16:51 +08:00
文章有时代局限性,现在都 2023 年了
|
54
Maerd 2023-08-19 01:06:27 +08:00 1
2023 年了,go 的错误处理还是一坨大便,泛型用方框号我是没想到的
|
55
beyondex 2023-08-19 02:15:24 +08:00 2
如果 go 语言是微软的,网络上一定是另一翻景象。精神股东太多了。顺便提一句,美国的精神公民也很多。
|
56
weijancc 2023-08-19 03:30:31 +08:00
@zzzkkk 现在前后分离, 意味着全栈, 学习成本会更高, 但开发效率吊打以前, 不过主要也是得益于 vue2 开发起来的快捷, 如果用 vue3 组合 API 或者 react 效率就可能差不多了
|
57
iceheart 2023-08-19 06:05:15 +08:00 via Android
用人当用长,
挽弓当挽强。 哪有十全十美的工具?挑毛病的话那就啥也别用了。 我喜欢 goroutine , 我喜欢丢一个 elf 就能跑。 我喜欢 go 的 cpu 和内存占用更低。 路由器上跑 go 程序无压力,跑个同样功能的 java 试试看👀 这些还不够吗?非要拿着放大镜去挑一个工具的毛病? 是不是有毛病? |
58
FightPig 2023-08-19 06:06:47 +08:00
@chaleaochexist rust
|
59
james122333 2023-08-19 06:57:34 +08:00 via Android
还好吧 什么过时的设计 blah blah blah...
多反回值有好处就是不用再写个结构包含其它资料 外加简单 没有花样 你第一次看程序可以方便理解 尤其学习底层的东西 至于 gc 貌似有个叫 arena 的东西可用 错误处理就没什么好讲的 不是问题 你要 panic, if err, 和 c 一样用 goto 都可以 |
62
ClarkAbe 2023-08-19 08:41:43 +08:00
假如那天我不写 Go 了那要么我去送外卖了要么我就死了
因为最初入 Go 的理由只有一个, 全靠同行语言衬托...16 年的时候 PHP 不给力 Java 感觉太...C/Perl CGI 写吐了...Rust 那个时候还听都没听过...然后最后看到 Go 就感觉这是神仙语言了, 二进制编译部署, 交叉编译, 协程并发, 健壮的标准库...也就自然接受了缺点 (其实那个时候也吐槽过为什么我的代码只能放 src 里面, 好在坚持两年后有了 Go Module) |
63
veike 2023-08-19 09:19:38 +08:00
@zzzkkk “laravel 的效率只会是 laravel 加 vue 的效率的二分之一”
那只代表你自己,不代表别人。 后台的前后端代码大部分都是自动生成的,写的很少。 "每天启动 node 命令的前端服务都烦 浪费时间" 这也只能代表你自己,不代表别人。写 npm package 维护多个项目感觉非常 nice ,少写了很多代码。 你写的项目应该是不用维护的那种吧。 |
64
Hanggi 2023-08-19 10:28:55 +08:00
简单来说,Go 语言是目前综合性价比最高的一门语言,单论某个方面 Go 都不是最顶级的。
但把性能、入门门槛、开发速度、编译速度、并发处理、资源占用等多方面综合对比的话,目前没有语言做得更好。 k8s 上的开源软件 8 成都是 Go 写的,所以真没什么可吐槽的,毕竟没有完美的语言。 |
65
ntop 2023-08-19 10:35:53 +08:00 3
两岸猿声啼不住,轻舟已过万重山
|
66
wkong 2023-08-19 11:03:54 +08:00
写了 8 年 Go 了 表示不服。
|
68
FrankHB 2023-08-19 14:28:13 +08:00
@Rooger 哦,路个过……我创造过不止一门,你创造了?那么我不闭嘴,你闭嘴?
(做梦,Rob Pike 假充内行在这里都不怎么配被我多送流量。) |
69
FrankHB 2023-08-19 14:43:59 +08:00
@wheeler 影响视觉体验和阅读代码效率,我是觉得和强行缩进一样欠揍。
@Maerd 简单粗暴,我喜欢。 要我就得说 Rust 那坨屑 union type 也是大便; Java 好歹有 exception 了但 checked exception 也是一坨不地道的 union type 伪装的大便; C 艹现在干掉了类似 Java throws 那坨 dynamic exception specification 了但是有 current_exception 和 __cxa_get_globals 还是大便(大概和 call/cc + globals 实现的 exception 差不多臭)…… 满目都是没有脱离时代局限性的大便,偏偏大便和大便的差异还挺大,要细细品味分析成分还是有些绷不住。 正常点没那么多消化半成品的错误处理应该是 first-class delimited control 之类的(也有 algebraic effect system 之类的冷饭正在流行),外加 local mutable states 可以实现的 exception ;至于 idiom 可以看刘未鹏的更上古老文。 @iceheart 长是什么?你喜欢的东西对你也许是够,对有本事自己造全套方案的,那就是吸引小朋友骗流量的生态垃圾。到底是谁的毛病? 就 go 那坨 variable 和 object 都拎不清的 spec ,能改?连 spec 都没二次开发(比如 C++ → C++/CLI )的价值的玩意儿,实现又是一坨(包括整个项目维护都有问题,loongarch 一坨问题 patch 交上去常年没人鸟),不整个弃还留着发酵呢? |
70
nuk 2023-08-19 15:31:55 +08:00
go 用来重写已经定型多年的基础软件还不错,公司里大部分基于 node ,java , 还有一部分 C 的东西都用 golang 重写了,部署起来确实方便,反正写好了都不很少改进。
|
71
lanlanye 2023-08-19 21:02:59 +08:00 via iPhone
编译快确实挺爽的小,写 Rust 就很怀念 Go 这点。
泛型和异常处理是真恶心,只要用 Go 写业务多了就能感受到(特别是我同时还会用 Python 写,开发体验可以说是两个极端)。 defer 这个坑还真没踩过,不过他说得有道理。 说来说去,Go 的简洁至少带来了一点好处:学习成本非常低,甚至不需要一周就可以掌握基础语法。 |
72
james122333 2023-08-19 21:22:38 +08:00 via Android
@FrankHB
exception? 这你自己封装就搞定了 为何一定得是语言标准... go 就是 better c 当然是延续 c 的想法 你不爽可以改 基本上我是赞同 Rob Pike 的 现在的软件过于複杂了 底层如何九成九的人都不知 loongarch 不支持是很严重 我本来都想买 |
73
picone 2023-08-19 22:46:59 +08:00
@EAFA0 遍历 map 加随机数这个是怕误用吧,如果看了 map 的实现就知道了,确实该加。
错误堆栈是因为 Go 一开始定位是 C 的优化版,所以没有这些玩意吧。 其他像泛型这些,感觉就是真香,这就叫“听取社区意见”。 |
75
cosiner 2023-08-20 08:34:50 +08:00
有一些是 go 的问题, 比如 error handling, new 函数, for-range 之类的
有一些是语言风格问题 有一些是作者本人想把 go 改成 c++ 只有第一类的问题值得讨论, 其他几个都算了吧 |
76
jinsongzhao 2023-08-20 10:11:32 +08:00
先关注业务后关注用什么语言,最后问问哪个语言可以为这个业务提供最高效和最低成本的投入。这样就不会对语言本身产生过多无用的争论了。
|
77
llwwbb7 2023-08-20 11:13:42 +08:00 1
这种对 go 的吐槽文章看太多了,但是他们宁可写这么长的吐槽,也不去提提案,把他们认为好的想法,好的改进表达出来,也不知道为啥
|
79
xinyu391 2023-08-21 09:52:03 +08:00
@araraloren 自带电池包,还是比较好的,省去了找各种库的麻烦。
|
80
xinyu391 2023-08-21 09:53:55 +08:00
文章说的有些原因,确实跟我体验一致。对于 Rust 同样有这种感觉。
以致于,想自己造一门语言,但随着了解的深入,感觉能力有限,哈哈 |
81
bv 2023-08-21 11:40:54 +08:00
敬请收看:驳狗屎文 “我为什么放弃 Go 语言”。https://chai2010.cn/post/golang/go-rust-fans-pk/
|
84
hez2010 2023-08-21 15:48:58 +08:00
@bv 可以点进去然后看他下一篇博文就是 https://chai2010.cn/post/golang/go-safe-interface/
这其实就是经典的语言设计失误才导致的问题,在没有从类型外部实现接口这种东西出现之前用鸭子类型倒是还能理解,但是作为一个 21 世纪诞生的语言就是纯粹的开倒车,只会带来一大堆的接口被意外实现的问题。 你可以看他前篇文章刚刚在“1.12 实现接口不需要明确声明”反驳了这个问题的存在,后篇文章立马就写这个问题的 workaround ,这不是自打脸了么。 |
85
dragonsunmoon 2023-08-21 18:35:23 +08:00
go 屎
|
87
haolongsun 2023-08-23 04:11:01 +08:00
@FrankHB 答辩看啥都是答辩
|
88
haolongsun 2023-08-23 04:11:32 +08:00
@haolongsun 不知道的还以为你是 linus 能够炮轰这么多语言呢
|
89
FrankHB 2023-08-23 22:16:42 +08:00
@haolongsun 你不用自我评价来体现你眼界不足的优越性。
你所谓的 Linus 是哪个?我是不清楚有什么配来评价的行家叫这名的。别的出名的,不管是 Linus C. Pauling 、Linus B. Torvalds 还是 Linus G. Sebastian ,不管在别的领域有多大成就,在这方面就是外行;如果不算你显摆无知外,和你说白了是同一个级别的菜鸡。 什么是内行呢?比如说至少也得徒手搓出 computation model 。 像 A. Turing 搓过 Turing machine 就是个这种 model ,但对应的语言就是 Brainfxxk 类似物,显然品味不咋地。他的老师 A. Church 搞个 λ calculus 就能把他吊起来打,因为比起除了 Turing machine 和 λ calculus 分别都独立起到极其重要的历史作用的 Church-Turing Thesis 外没实用性的 Turing machine ,λ calculus 事实上定义了高级语言——它能扩展出绝大多数实用语言,不论这些语言的设计者有没有意识到。而 Turing machine 可没多数人意淫的超然地位,同时代的现实的 computer 都根本就不参照它设计,就没起到演化出 computer model 的作用,如 C 厨二随便一个 PDP-11 式的 PRAM(parallel random-access machine) 都能把它摁着摩擦,刷存在感抢功劳还有点在看不起至少在 EDVAC 就明确区分外存和内存的 von Neumman ——尽管 computer model 比 computation model 天然次等,而且这还不是他一个人搞出来的。(其实 Turing 也搞过早期的 computer model 然而多少被无视了。) 但即便是 Church 这样的行家,也会有掉链子的时候。他曾经鼓吹 λI calculus 代替 λK calculus ,就是因为逻辑侧的完美可推理性质的执念导致不能表达偏可计算函数,因此后世还是用 λ calculus 指代 λK calculus 而非 λI calculus 。绝大多数已经受到前置严格训练到能手搓新 model 的专业人士,同样在天赋上就突破不了 Church 的这种程度的历史局限性。 回过头来看,你所谓的 Linus ,不管是哪一位,比起 Turing 的水平,还不是被随便踩扁的蝼蚁?而 Turing 在高级语言计算模型设计的码品上不过是个菜鸡不如的小角色,都不知多少人好意思拿他代替 Church 的地位。然后你还有脸在武力值早就突破 Church 这个层面能取得系统进展的行家面前提什么玩意儿? 连手搓语言都不会,也配来洗地? |
90
FrankHB 2023-08-23 22:55:11 +08:00
@james122333 这其实是个很有讨论价值的话题。
首先,你意识到异常可以用“封装”实现,已经可以碾压一堆麻木不仁的无能用户了;但就有个直接的问题:被封装的是什么呢? 有没有想过,大多数语言设计者会去考虑直接内建异常,就是为了逃避被封装的对象在理论上的理解门槛(都先不用考虑异步异常的复杂性),或者更甚——压根就想象不出这些东西? 先告诉你结论:在有可变状态(比如能赋值修改对象产生副作用)的语言,异常可以用一等续延(first-class continuation) 配合实现。而更基本的有界续延(delimited continuation) 可以凭空在语言里添加类似赋值这样效果的可变状态支持(当然这不是纯 FP 语言,续延调用本质是一种副作用)。加上定界的原语,直接用控制作用搓出整套异常也不是不行。(顺便,现在那些 FP 人搞什么 algebraic effect system 其实是 delimited control 炒冷饭。) 为什么一般所谓的工业界语言不这样做?除了不够方便利用硬件实现外,最主要的原因就是——那些语言设计者太菜了,这点基本的弯弯绕绕都不会。而 Rob Pike 在这方面其实就属于平平无奇的太菜者之一,偏偏还比较喜欢不懂装懂(虽然这里没有特意显摆如何犯傻;别的像区分不了 nominal type system 和一般 type system 已经是普通用户都能领会的语言设计业界的笑话了)。 结果搞笑的是,这些设计者看不透复杂性具体在哪,聪明反被聪明误。一个实例:像 C++ 这种语言 spec 内建异常看似不弯弯绕绕简单了,实际上 ABI 黑魔法一大堆,并且几乎阻止了绝大多数有现实意义的优化(以至于使“异常”多背了几倍性能差的黑锅;其实就是 bad path 本来也不需要那么差,更重要的是 C++ 异常烂不表示没有更正常的,比如 ML 系的那坨)。——注意这种优化不只是 ABI 过度设计问题,current_exception 这样语言上的机制也有锅。知道菜人占据主流地位的危害了? 当然,理论上异常也是有一些不方便被续延之类的控制原语取代的性质。这方面么,有篇入门读物 Contrasting Exceptions and Continuations 。入门以后大概就容易理解为什么虽然 C++ 那种异常设计已经足够欠揍,还是要更鄙视“连异常都没有”的无能语言了。(当然,有续延自然论外。) |
91
FrankHB 2023-08-23 23:18:15 +08:00
@wheeler 妄自尊大的 UNIX 无知厨二出线一次,没被人人喊打,即得而诛之,免得路人习以为常传染反智病毒。
有个更明显的例子:{ 不换行要往上缩,为什么 } 还要单独占据一行?有厨二所谓“省行数”,当诛,因为这是侮辱智商:真要省行数为什么不用 LISP style 把 } 缩到上面一行? 再者,为什么 K&R 风格控制语句的 { 和函数定义起始块的 { 换行规则不一样?这也是厨二解释不了的。真正的原因其实是早期 K&R C 的声明语法造成的上下文差异。K&R 厨二八成连 K&R C 都不会,殊为可笑。 不屑评价这种无聊问题,本是正常状况;但遇上自己脑子里没货还非得硬洗的,要哪壶不开提哪壶污染视线怎么办?除了直接镇压没什么更有效的做法。虽然我仍然时常希望不用每次我来普及那么入门的基础,但什么都不做只会更差——要是没人反驳,搞得反智者就天然有资格指鼠为鸭了一样。 不经大脑以讹传讹者同罪。 |
92
FrankHB 2023-08-23 23:40:18 +08:00
@llwwbb7 我就奇怪你有没有视力问题,更奇怪为什么还有人给你点感谢。嘲讽?
原文: > Go 语言社区里,有一大批 Go 语言的推崇者和脑残粉丝,他们满足于现状,不思进取,处处维护心中的“神”,容不得批评意见,不支持对语言的改进要求。当年我对 Go 语言的很多批评和改进意见,极少得到他们的支持,他们不但不支持还给予打击,我就纳闷了,他们难道不希望 Go 语言更完善、更优秀吗?连基本阅读理解水平都你不知道还好意思分享了? 看完文章你就该知道 Go 的支持者对维护者以外的人做出的改变(不论是否是改进)的大概的态度了。 Go 社区拉一般用户仇恨根本不是个别现象,也很少有别的语言社区能作到这个程度的,如: https://github.com/hhstore/blog/issues/348 虽然那个普通菜鸡水平只能让我归类为“一般”用户。 不那么一般的么,比如信创行业要为 go 上游放置某些国产后端 issue 几年不鸟、工具链实现质量炸翔的原因,要把 Go 厨二挫骨扬灰的也有——毕竟屎淹到脖子以上了,看厨二还能呼吸得逍遥自在,不爽也不是不能理解。 相比之下,你这风凉话就是事不关己高高挂起的小丑了,连 Go 官方都不如——后者好歹还在做事,虽然未必做人事。 |
93
james122333 2023-08-24 02:35:31 +08:00 via Android
@FrankHB
计算机世界都是筑高塔 go 不是没异常 只是要简单封装而已 称不上複杂 只是更原始的东西更好 因为现在塔已经太高 很难学到东西 大部份程序员就是整天研究别人搞出来的大工程 除了应用技术一无所获 甚至以应用技术为豪 大家自豪的又不同 我更认同 Rob Pike plan9 也很不错 |
94
llwwbb7 2023-08-24 11:55:36 +08:00
@FrankHB 我说风凉话?我让对 go 不爽的去提提案就是说风凉话?怎么,你就是那个光嘴炮不发提案的人,我戳到你痛处了?
我是事不关己高高挂起的小丑,你呢?事关你了,你干什么了?你像个怨妇一样说这个菜鸡那个无能,你算什么?你既然自命心比天高,你也去搞个语言,把那个垃圾 go 干死,荣登编程语言第一宝座,怎么样?回头我也能作为你传奇故事里的小丑露个脸,不错吧? 等你的好消息 |
95
FrankHB 2023-08-24 14:10:02 +08:00
@james122333 不说立场,你得先弄清楚对事实状况有个基本了解才有讨论的意义。现在就鸡同鸭讲。
Go 哪来的异常,连 Rust 那种烂掉的 union type 都没。Java 的 checked exception 是滥用语法重载(偷换 try/catch 的含义)的阉割版 union type ,都够流毒无穷了。 基本知识问题麻烦善用搜索引擎,不浪费字数了。 我就再提点你搜不到的:异常和续延背后的东西是控制作用(control effect) 。不论静态类型还是直接不支持,那就是在恶心健全的用户,因为想要克服这种限制原则上只能自己掀翻重新造一个不那么无能的语言。要是用户无能到想象不出还好(虽然考虑到这些限制的普遍性,我就看不大上自己没搓语言的用户的观点),想要剥夺已经被享受过的自由,那只能靠愚弄了——一如纯 FP 语言鼓吹者对传统命令式语言用户洗脑“副作用是邪恶的”。 Rob Pike 这种尚且能被不会独立设计出的普通用户黑出翔,至少语言品味上的道行显然不值得我评价;最高也就是道不同不相为谋,但这是贬低的不是他一个人(他不配;其实 Go 都不是他自己的作品,黑他主要就是水平烂见识短),而是所有自甘堕落因为自己想象不出该怎么不对无能的语言妥协就恶心别的用户的卫道士的总体。至于 Plan 9 ……,(以整个 OS 作为大号语言运行时的实践)历史地位上就还是算了吧。UNIX 什么 everything is file 是比鼓吹 everything is object 影响还大点,我倒是有黑过。 |
96
FrankHB 2023-08-24 14:20:36 +08:00
@llwwbb7 我见到的不管是或者不是周围的都有人去实际行动过,效果不忍直视;而我本人看不起把持 Go 的核心人员的工程不作为,所以不屑浪费精力肉包子打狗,这也解释得很清楚了。
直说吧,WG21 现在的提案质量大多数都相当垃圾(什么没事整个 char8_t 改 string literal 类型后进到过了几年知道有 bug 了认怂回档但是发现进不了 deadline 还得再等 3 年进下一个版本)到一人一票制下我都懒得关心(而是不得不提 defect 擦屁股),我又不用你 Go 赏饭吃,外加你个 Go 对整个工业界的那么丁点(还嫌多)的存在感,你个 Go team 也配碰瓷我工时? 就算不清楚别人什么水平,想不到这点,那你看过文章了没?对 Go 不爽的 Go 用户去试图提意见改进的这篇文章作者就干过,然后什么效果? 那么,你呢? 有没反思过我为什么评价你高高挂起?因为你在这就没什么行动,撺掇别人上,自己光说不练,也没说清楚你有什么立场光说不练。 |
97
llwwbb7 2023-08-24 17:33:25 +08:00
@FrankHB 搞笑呢吧你?我又没有不满,我练什么??谁不满谁上这道理还得我教你??
我的立场?我就是看不惯你们这些觉得老子天下第一,这不满那不满连个提案都提不出来的垃圾,就是要嘲讽,怎么了! 你自己都说提案质量大多数垃圾,你凭什么就觉得所谓这篇文章作者提的就不垃圾,凭什么 go team 就得接受??你第一天进开源社区?不服自己 fork 你不用 go 赏饭吃,go 也没有存在感,你又看不起 go 不作为,你在这上蹿下跳的干什么呢??吃饱了撑的? |
98
FrankHB 2023-08-26 16:35:56 +08:00
@llwwbb7 搞笑了,这文原作者就是明确表达不满,然后我补充一下为什么不满的原因以及作者说的并非个例,而你又在说啥?不但扯没点实际可操作性的风凉话,似乎还想表达别人不配不满?那我只能说,我有充分立场说我也看不惯,是因为我本业界绝大多数用户都更深入参与有关工作,属于核心利益相关者,如果我不配说这个那么 v2 的 99.9%以上用户怕是都不配。而你看不惯……怪了,你是业内核心人士还是什么知名人物,算老几?还什么开源社区什么 fork ,你去 fork 出个东西人家自动会鸟你?
还有你阅读理解有问题。我的确是看不起 go ,因为 go 设计在理论上就是垃圾,但这里本就没说这个话题(原文说的主要是实用性缺陷),而且原作者后来鼓吹的 Rust 实际上也没强哪去,所以其实我没怎么提。我重点鄙视的就是某些人生产工程废物,占着茅坑不拉屎,浪费市场资源,人人得而诛之。你有意见,是不是想被一起吊起来拷打?然而尴尬的是你这里看来只有废话,没表达什么技术观点,更别提能被评价的和 go team 干活类似的实际贡献啊……连被吊起来的资格都成问题。 退一万步讲,这篇文章作者见识再有限,至少比你这种大声嚷嚷“我就是看不惯”,然后通篇实质性技术论点都没表达半个强不知哪去了。 |
99
llwwbb7 2023-08-26 17:35:47 +08:00
@FrankHB "但是他们宁可写这么长的吐槽,也不去提提案,把他们认为好的想法,好的改进表达出来,也不知道为啥"
"我就是看不惯你们这些觉得老子天下第一,这不满那不满连个提案都提不出来的垃圾" 我就是看不惯你们这些觉得老子天下第一,这不满那不满连个提案都提不出来的垃圾 |
100
llwwbb7 2023-08-26 18:02:23 +08:00
@FrankHB 你“补充一下为什么不满的原因以及作者说的并非个例”,我在说啥?我在让你提提案,提提案没有可操作性是吗?
你属于”核心利益相关者“又怎么样? go 是开源免费的,go team 又不欠你的,你给 go 做过什么贡献?你不就是个依附于开源社区的蛀虫吗?趴在开源社区身上吸血你就觉得自己了不起了?谁给你的脸?你又是业内核心人士还是什么知名人物,算老几?凭什么 go team 就得听你的? 你也知道你 fork 的东西没人理?那你还 BB 什么?只能说明你就没那本事,你说的就是错的。你要是对怎么会没人理?让你去做一个比 go 好的语言出来,你怎么不敢呢?你那么厉害,你倒是做啊? ”某些人生产工程废物,占着茅坑不拉屎,浪费市场资源,人人得而诛之“??搞笑,你又生产了什么比废物强的东西拿出来看看?你没浪费市场资源?怎么不先把你自己诛了? 少在那自我感觉良好了,你还”实质性技术论点“,你那么有技术论点你去提提案啊?提不出来,你技术论点再多也改不了你是开源社区的蛀虫,吸开源社区血的事实!你都核心利益相关者了,对 go 一点回馈都没有,端起碗吃饭,放下碗骂娘,臭不要脸! |