破案了。
TL;DR:
我一开始没注意到就有 cdefs.h
里本来就有 _containerof
,就是 drm2 这代码没有用。
你要是有看到了,早提一下,就不会那么多问题了。
FreeBSD 如何对待 container_of
其实是个很琐碎的问题,也并不全像你说的那样,就只是因为非标准而拒绝。既然提了,那就彻底一点。
其实宏 container_of
早有被提议过,但被拒绝了;作为替代的就是 __containerof
(正巧主要就是用在链表实现)。
如你所说,这位开发者认为 container_of
是 Linux 用的;然而更具体的理由是不想污染 userspace 。
从 __container_of
的提法,可以看出知道 userspace 里有应用,所以这说的是不适合用不带 __
的标识符从污染到 userspace 的问题。
这里也提到和 Xorg 可能冲突。虽说 Xorg 显然就只是 userspace 的代码不会合进来(银河麒麟情绪稳定(?)),不过免得无脑复制粘贴出问题所以还是叫不同的名字好了。于是最后有了 __containerof
。
不用 __container_of
的次要理由是宏命名不太一致。但这说法意义不大,因为 C 以前不在标识符中间加 _
主要是标识符长度限制,一旦取消这个限制就会自然混用 xxxyy
(历史遗留代码)和 xxx_yy
(新的代码),而且 of
前是否应加 _
是个自然语言分词问题,根本说不清楚。我也没找到 FreeBSD 有明确禁止这种命名。
这符合我的核心观点之一:提供 container_of
背后的功能和 Linux 没关系。(点题:)用 C 造轮子迟早得有类似的东西,这就不是特定于 Linux 或者内核的需求。
所以说,就是我想的东西,FreeBSD 核心开发者早几年就想到了并解决了。
比较尴尬的是,__containerof
是不需要依赖GNU扩展而更可移植的。({})
和 __typeof
只是多提供了一个类型检查而已,是可选的。反而那个 container_of
一定依赖 ({})
,而更不可移植……
……现在看来,就是 drm_os_freebsd.h
的作者大约不太熟悉 FreeBSD 源码,合代码的也没怎么在乎质量,没 #define container_of __containerof
而已。
(不过这还只是个 container_of
。别的冗余还有多少呢?)
说人力不够我懂,不过这不就是承认了没充分 review 过而没法解决问题嘛……
题外话:
技术上,container_of
是否能严格可移植地实现和使用,仍然是个不够明确的问题(这里还暗示它的普遍性和Linux内核没什么必然联系,虽然 Linux 可能加快了流行)。
但可以确定,现有的 C ABI 普遍允许不依赖 GNU 扩展的实现——至少除了故意,我不觉得有生之年 FreeBSD 开发者能摸到一个实际实现不了而毁灭可移植性的配置,所以 __contianerof
也基本不会有问题。
list=empty|(list,data)
这最早来自cons pair(许多list是实现sequence的proper list,还有附带data=list的约束)。但这里没提cons(除非实现Lisp之类,类C语言传统就不吃这套),属实sum type fans还来念歪经了罢……抛开cons,这还真不兴叫head。
不过我的重点是强调应当避免混淆cons pair和list这两种抽象上根本不同层次的东西(至少在没GC兜底还有副作用的语言里;依赖unsafe算不可抗力,也是Rust链表笑话的直接来源)。前者只是后者的一种实现;并且考虑一般语言的默认的所有权规则,前者自然地会附带不必要的限制而可能产生行为不同。
只有取不计较所有权的view和访问个别元素时,这种不同才好忽略;不巧,用了C,你迟早得显式说清楚分配和释放资源的时机(毕竟没函数实参求值顺序那样直接在语言规范里钦定“未指定”,都没法在一份代码里写出“未指定”所有权的实现),所以没文档时,不挖开具体实现看,就不太好确保这真是你要的(有没有不小心依赖资源释放顺序之类)。
其它语言大多也有这问题,如C++标准库容器析构元素的顺序不能指望,这没法用C++代码表达清楚;但起码你能明确真不能指望了。偏偏除了C,别的语言基本都有现成的能说清楚这事儿的API,而不需要你用户自己山寨实现……
有啥类型系统和接口定义得比较讲究
要接口清楚,基本不会直接说是“链表”,而得要有个类似list monad或者sequence的ADT(典型地,就叫list类型),屏蔽掉是否依赖cons pair甚至几个link field的实现细节。
不过要把更抽象的sequence强行放在一起,不管用什么方式都可能比较蛋疼。这两天doi:10.1.1.72.8645附带的代码看到抓狂,发现里面用了variant的seq基本只是为了抽象而抽象,各种意义上都不如语言直接提供的原生list;我打算把这个当作manifest typing抽象清楚反而更糟的反面教材用。
像古董LISP一样万物基于atom+cons pair好像也没啥,设计还挺一致,但这下就真没抽象的list了;把list作为pair的子类型更不对劲。而且实际不大够用:现在的Lisp很多也另外提供vector;退一步讲,string只要能访问单个元素,数学上就是个vector,也是一种list。
这个意义上,像C++这种提供多种container,明确告诉用户有公共API,不同的是复杂度(也只是给人看,没类型系统支持)和个别附加操作,是更加正经的设计。当然C++的具体API也不干不净——光这命名就呵呵:凭什么传统的array你这叫vector(/array/map/unordered_map/...),string你这叫vector,vector你这叫[val]array,然后还冒出来basic_string之类的什么鬼?凭什么vector不能SSO?凭什么!noexcept(deque())?……
为什么 target 调用后是 owning ?
所有权具体表现为调用后需要谁释放资源的职责(当然intrusive就no-op)。
C指针的语用习惯在表明所有权上一向特别混乱,不另外约定代码里基本没法看清。包括我提的改用返回值在此仍不够清楚,如WG14 1174表明ISO C和POSIX的惯例都不一致(虽然WG14现在好像吃书了)。
C++除指针外,同样没检查,得用户自觉,像内建引用也能硬拿到指针再搞事。但要去没事delete自动变量的引用这样找茬,极容易在代码审查时被发现并干掉:delete这种不能自动维护不变量的东西就不该允许日用,不看操作数都能直接当敏感词鲨了。
也就是和讲不清所有权的内建指针能有一腿,想讲清楚总有更好的选择,这种才能当敏感词而不怕错杀。于是审查一般C++代码就能偷懒一刀切:“new/delete是给你用的?恁也配泄露实现引入超额复杂性?”——如此快速干掉大量鉴别烂实现的成本。
C这里就抓瞎了,自作聪明的“资深”用户比语言抽象无能都麻烦。就算意识到能强制要求用不透明指针/句柄,都得防着点是不是会有拿类似Linux kernel coding style“不准多_t”的教条说事的。相比之下,要判断这里所谓的taste如何还是小儿科,只是不怎么idiomatic,会有争议而需要维护者多费点劲调停style差异(虽然我是觉得都挺烂的而相对无所谓,反而用别的更清楚的方式也确实容易啰嗦而不自然——谁叫你用C呢)。
至于具体到实现list而非cons pair的链表,明确需要non-owning引用,如用observer_ptr代替内建指针。但大多数情况下,可能还不如:“你也配自己重新造链表?”——别笑,避免自作聪明乱实现基本数据结构真是不少工程的刚需。
这些乱象导致C++开发体验看似不比到处滥用unsafe后的Rust强,不过用户被逼自觉后,破事反而少。
为什么 erase_after 传了个 const iterator 进去,好像 ownership 上也不对劲
和C++内建引用类似,iterator(不限C++里的)一向是non-owning(不管是看历史还是现在的concept),别故意搞事就不应有混淆所有权的问题,至少比一般指针更难(搞事一般得故意&*搞成内建指针来用——还是指针在捅娄子)。
const_iterator erase的问题主要是const correctness。对这种用参数指定位置而非访问元素的insert和erase等,禁止const_iterator不必要,反正erase要求容器自身non-const已经够correct了。于是WG21 N2350修改了这点。erase_after也一样。副作用是实现内部几乎不可能免掉const_cast(要么强行转发给mutable成员),但非const容器放在只读存储实现也不大有意义,所以也不用担心UB而没法可移植地实现。
除了免去用户的一些需要另外存iterator而不是const_iterator的值的蛋疼问题,另外还多提供了一种用con.erase(i, i)实现const_iterator→iterator的cast而表面仍然type safe的hack……挺好的。
总觉得有strict aliasing的问题……看起来是不会出 UB 的
这个是 C/C++标准明确允许的指针转换
C是允许类似的转换,当然语法不一样。
C++17以前没有明确允许这种转换,按CWG636(尽管没针对non-union)这里也是说不清楚的,而layout-compatible能做的相当有限,特别是一个指针根本不能跟类类型兼容。
只不过跟C兼容的意图导致实际ABI没法做别的(除非C ABI就允许指针的对象表示加padding给tag或者NAT bit之类的东西,反正我是没见过),似乎也没实现TBAA sanitizer照顾这种例子,于是就算用C++17以前的实现自然也没法测出来。
直到WG21 P0137修复CWG636时顺便添加了pointer-interconvertible,修改个别转换规则,这里的含义才算清楚,重新明确允许和C类似的这种转换。
不好意思,不记得你谁了……
那么多年还C/C++?是你太盯着C和C++了罢。或者你关心的有的地方我觉得比C/C++还low太多我就不掺和了,跟你没交集。
(实际上,要不是最近还有isocpp.org/files/papers/D2583R0.pdf这样的瓜能吃,或者偶尔有人咨询defect和一些进度问题,我都没在鸟WG21了。)
毕竟人总是要有点发展的,不能总是停留在一个圈里,你说对不。
虚空论道你还得看Linus Torvalds,虽然他的设计(比如git的CLI)和实现(比如这里的C代码)的taste真不大行而被很多稍微内行的(包括一些非开发者的普通用户)批评而有争议,但是不畏强权找皮衣黄fxxk事的本事,应该公认没几个人做得到,倒足够当吾辈楷模的了。
注意说Linus是PM并不是贬低,因为对Linux这种规模的项目来讲,一个靠谱的PM能做的比普通coder能做的多得多的多。要是一个leader同时每天写那么低层次代码,基本不是当消遣就是不务正业。
前几年有报道Linus介绍自己的日常工作主要是读写邮件+合别人代码的时候,我还奇怪这居然需要特别澄清么……结果发现还真很多人不知道他干什么吃的。而你似乎是到现在还不怎么清楚的亚子?
至于不普通的coder,在Linus负责的几个项目干活的基本是没什么机会的,因为能实用的局部实现技术都是别人的地盘里玩剩的——至少没什么足够发正经paper的高精尖的问题;要是发明个promise/future/engine之类的,用C就是虚空堆难度,这辈子基本不用想了。
比较有名的C用户里,大约也就Fabrice Bellard有在“不普通的coder”方面搞事的能力。但他自己搞出来发表的东西除了一个改进的BPP算法(主要突破也不是coding),基本上仍然徘徊在严肃科技和玩具的边缘而相当鸡肋(比如QuickJS果然就差ES6 PTC没实现);而他搞起来的实用项目(像FFmpeg/QEMU)跟Linux一样,大多数设计实现就不是本人的贡献,以至于一开始工程上轻量的优点随时间的推移迟早会被磨平。所以他要不再搞点与众不同的新东西,生涯成就跟普通coder比下有余,跟理论界工业界一线水平相比还比较难摸到边,不过如此了。(有的人确实看起来不那么兴趣广泛,不太可能出圈、被大多数“社区”成员知道而深藏功与名。)
相比之下Linus的coding水平简直就是泯然众人了,连taste的不同其实都不怎么值得讨论——不管是好是坏,都没偏离均值太远。我在这里吐槽,总的调门也就是嫌弃均值太low罢了(下限比Linus更low的自然多了去了)。
说Linus是“社区领袖”虽然不假,但拿这当主要头衔,搞的人又像每天都在竖中指运营造人设一样。和讨论不着边际的taste如何重要一样,安排这种头衔看上去就像给网红穿皇帝的新衣。……啊对对对,人家的主业确实不值得你有兴趣了解和尊重是吧。
所以小丑竟是?
#113
许多(只会)C用户被人鄙视的理由,主要是他们分不清什么叫“背后”,却积极擅自决定什么应是台前什么才是背后,给他人添堵同时撺掇话语权。
明明作为客观现象,一般工程普遍就自上而下从整体到详细设计再到实现,值得关心的部分有很强的相关性和因果性,偏偏这些人就不管先来后到,乐意中间抽一段半吊子的C(大约是因为他们只会这样),而不管跟这些人说更高级的抽象还是更基本的实现(包括但不限于汇编、机器码、微架构特性)基本都对牛弹琴,经常还自我感觉良好。这就比较拉仇恨了。
(本想说熟练C的用户,不过只会C的用户不大可能熟练到哪去。Linus要熟练C而不是C的半吊子实现,对-fstrict-aliasing也不该有奇葩调调;而且Linus至少也还熟练ix86汇编,即便不大算是专家。)
被这些用户关心的东西,很多连回字有几种写法都远远不如——好歹这个问题描述是清楚的,解法也很完整,除了分散应该关注的问题不容易凭空增加次生问题。
就比如说,这里除这些C用户,谁会真的先在乎具体几级指针,而不是接口设计对不对或者生成的目标代码实际是不是符合预期?
本来这楼OP里说的才是绝大多数情形时的真正的“背后”,是在拎清并解决主要问题下才需要考虑是否有必要“优化”的细节。搞清楚先来后到,就会对这种所谓的taste论一笑置之了。
结果让我大跌眼镜:那么多回复的,真卷到多数都在纠结这种次要旮旯问题的程度了嘛?我只能:???
说实话,光是我来先指出接口上的不合理就挺吃惊的——就算这里不太有native开发者,不至于那么点审查设计合理性(甩锅)的基本职业素养都没吧。
再如所谓的析构,明显就是有意为之(抄的Common Lisp,但和这里说的没直接关系):默认保持不变量,保证和更需要用户关注的业务逻辑的关注点分离。
要是真觉得某一块逻辑应该显式搞出来才清楚,那么就不应该放析构里。
还是拎不清,那么说明没搞清楚什么应该算“背后”。这是很离谱的,因为任何写过有点起码的可维护性的资源管理代码的都理应清楚这些代码之间有哪些重复和不小心漏了可能会有什么后果,知晓自动保证带来的相对收益,了解把这部分逻辑算“背后”的机制的动机。
这点基本和高频的常识性实际需求都无法理解(没无师自通就罢了),还能大言不惭地嫌弃“背后”行为太多,唯恐这种在读者面前分散注意力的逻辑不够碍眼,基本就不适合干这行了。要坚持这种观点写这种代码的,怕是在嫌资源管理不够乱而找正常开发者和最终用户(比如被double free bug到的)的揍。
与之相比,纠结回有几种写法,显然人畜无害得多了。
至于C++,我就只是顺便当靶子。抛开和其它语言共享的缺陷,C++总体也并没好哪去。(虽然很遗憾,光有个析构就能把不少语言摁在地上摩擦了。)
我从来就没少批评C++,且比批评C刻薄得多——因为C除了各种用户不懂的历史,专家对大多缺陷认识得相当清楚,确实没那么多旮旯需要批评的;再加上被抄的设计太流行,原则问题基本在批判其它地方时三两下顺带就能盖棺定论。而C++用户自作聪明纠正起来通常更困难,后果经常更严重,其中的主要弹药就是C++自身的复杂与冗余。
问题是这些批评中较容易理解的部分,绝大多数C对应的都做得更烂/废(比如上面提的扩展和C++的lambda的对比,虽然本来不是做一种事情的);论据里另一些算不上多难理解的,只会C的用户都直球看不懂(却又经常不愿说哪里不懂)。更不巧地,因为C++和C(表面上)比较兼容,这部分用户很多稍微摸过一些C++(但算不上会),也基本没别的语言的经验,只是跟一些初级C++用户比较有交集,而发现特别方便直接对比开发体验,结果菜鸡互啄(互相)嫌弃到伤玻璃心,就好像以为被C++(C)用户针对了一样。(可以自信点,其实这些人是在大多不只熟练C的用户开战。)我首先不满这些人有意无意混淆视听。
由于现在还会特别以C用户自居的主要就是这部分人,所以批评C用户“不学无术”整体实在比批评C省事太多了。(当然这缺少建设性,所以我好多年不拿这个专门氵文章了。)
就现在这教育水平,放着这些存量失败用户不管,就从不会缺被传染上自以为是习性的新用户。虽然搭理这些用户不怎么愉悦也没什么收益,误导更多本来能少走弯路的初级用户这件事本身令我更不爽。所以就是不定期破事氵的状况了。
Appendix:
实际上(非平凡)析构确实有致命的弱点:和PTC(proper tail call)一定程度矛盾。(除了析构,类似地,还有Racket这样的contract等等。)这个问题在理论和实际上都非常麻烦,至今没有圆满解决。
后果是限制可扩展的下限:如果要简化语言到一定程度,基本就是得重新自己造解释器写新语言。虽然很多个别残废设计也会导致这样,但我是没看见别的单独一整个特性缺失会造成更严重的问题。
大多数用户对这里问题的严重性感知不强,因为就没怎么享受到白嫖现有实现直接扩展语言特性的权力(macro considered harmful)……从没得到自然就不大会计较失去了。
所以换个方式比较。例如,类型系统表达或者抽象能力垃圾是一个语言被嫌弃的常见理由。实际上如果别的扩展性设计智商足够在线,语言类型系统残废甚至整个不给你显式类型系统,都不算个什么事儿,大不了另外往上加,用户自己都可以另外写个预处理翻译过去;至于魔改以后是不是还算一个语言(ES→TS vs. PEP-484)就另说了。
(因此我也历来也不大待见吹类型设计如何如何的“理论”家;因为那相比之下真的就是主次不分或者弃疗到一定程度才会去纠结的“实现”细节。因为类型系统设计的不成熟,提前拉出了API兼容的屎遗臭不知道得几年的例子也不罕见。真会玩的,信手拈来虚空出类型当工具人来解决问题的奇妙深刻方法可是不知道高哪里去了,如legacy.cs.indiana.edu/ftp/techreports/TR611.pdf。)
C/C++用户普遍缺乏感知,除了教育背景问题不够清楚这里的代价外,主要是传统的设计压根就没保证过PTC,有的撑死只是TCO/sibling call之类的可选优化;但这里谁该负认知偏差和集体摆烂的历史责任,就有点鸡和蛋的问题了。加上很多用户先熟悉了C/C++再拿别的语言往上套,就更说不清楚锅在哪了。
在这里我不特别针对上述C用户(以及大多数C++用户)开火,还同样有“先来后到”的原因:因为至少工业界现在还在继续摆烂。
这个问题,Guido van Rossum这种在若干年前还需要feel educated然后十动然拒、TC39在ES6加入PTC后还要step back圆润出STC毒害恶心所有其他人(至今主流实现就Safari才支持PTC,猜猜这里有多少人清楚v8是什么可笑的原因残掉的)、就是写Lisp编译器的都有拎不清PTC和TCO的差别而欠教育的……“专业人士”mdzz的症状多得要命,就算是重要的基础课,哪轮得着浪费资源向补不完更多其它基础课的C/C++用户宣教呢?
“实时”的 RAII
C/C++不保证实时性。
大多数C/C++实现的程序都在分时系统上运行,受到系统限制,软件上就不可能实时到哪去。
硬件上,至少主流系统不行。例如,你访存换页,不巧页面文件里访问到了硬盘坏道,内核驱动也没检查并强制超时失败(很常见),那可能整个系统就卡死了,GG。
(这也直接报销掉了指针访问是O(1)的错觉;尽管C从来都没明确的保证,而C++只是在把内建指针当随机访问迭代器时有这种会被实际情况打脸的保证。)
当然,实时定义上就是相对的。严格的实时都要加时限,而把时限放宽到宇宙年龄也没什么意义。
没指定具体时限可导致能称为实时GC的实现也不保证你要的性质。
所以你所说的“实时”,大约是同步,即便不够及时(实时)至少局部操作的一些逻辑顺序是可以预测。典型GC一般是异步(并发)的,不保证这点。
同步实现更简单,在析构上进一步还保证了确定性。这个坑少,你说的没错——前提是析构要写对,不要太卡(应该不难)。
然而真遇到耗时操作,全同步会实际阻碍应用层次的实时性的实现。
典型情况是一个GUI应用卡了,得指望外部的系统给你画个没响应的界面用户才能点得动,而不是应用自己响应。
一个原因就是异步太难写了,默认同步直接阻塞超时就没法补救。所以现在C++算是在改进这方面,虽然体验将会长期比较呵呵。
另外C#所谓的析构(destructor)是微软文档的私货。ECMA的C#国际标准直接就注明这应该叫终结器(finalizer),而所谓的析构就只是你想要的那种。只是ECMA多少年不更新了……
不过你用稍微深入点用过C#的,应该很早就遇到过的想要的东西,叫Dispose。它不像C++的析构那么普遍隐含调用,用起来相当麻烦。
后来C#有了using语句,退出局部块调用Dispose,跟C++自动变量RAII体验差不了很多;连Java后来也有了try with resource。
但这些仍然不支持C++的析构能跟随对象传递到作用于外部。
前几个月微软Wang Mingxin曾提议把C# Dispose改进成类似C++析构这样的,但没有被接受。
所以光看这方面,你算是赌对了;大多数语言现在仍然比C++麻烦得多。
顺便:
1.C++的异常处理是同步的,同步过了头——可能阻塞所有线程,以至于现在有人为了主流实现不能并发unwind性能差伤脑筋。 2.硬件异常可能是异步的,可能还同时快不到哪去,就更头疼了。这翔不用给写应用的吃——除了C/C++的信号处理等少数例外。
container_of 对于 FreeBSD 来说还真的不是“通用代码”
不管是不是FreeBSD,container_of这个API不论知名度还是功能普适性上就已经够得上通用代码了,跟offsetof几乎就是同一个层次的东西(基本就差没被标准钦定)。
要把这种东西藏起来私用而不惧可能的冗余,要么就是跟流通的API实际很不同的东西(很可能说明命名品味糟糕;不过C宏名嘛……不是不能忍)。但这里并非这种情况。
FreeBSD 的这个 drm 文件,实际上它来自于 freedesktop.org
我能理解这个文件来自不同的上游(从drm这名字能就猜出大概怎么回事了);但既然没放在源码树的3rdparty/vendor/contrib/external这些明显可以跟自己撇清关系的目录以外的地方(按常理讲这就是maintainer会接手当owner的标志),就有点怪了——特别是这个文件来自于几乎算是最重要的freebsd-src的顶层目录sys,而顶层还真有另外叫contrib的。
当然,这和我自己习惯的项目管理和协作风格有关:默认使用源代码目录负责制,一个子目录的owner对下面所有子目录的负责,除非子目录还有更具体的负责人。这时候子目录起码得有个README,而且没AUTHOR/CONTRIBUTER之类的话owner自己就应该能行使作者权。这种做法的明显好处是局域性:协作维护源码树中的文档不用东跳西跳。
不过freebsd-src的这几个目录里也没有说明文档(我不清楚是不是故意移走了)。
虽然FreeBSD的Handbook很好很强大,但项目开发文档,尤其是in-tree随源码一同版本管理的一手资料,就不适合被用户文档代替(容易缺乏局域性是另一个理由)。
同理,man通常也不算是很正常的获取源码树使用方式的正确姿势。
更别说公共头文件了。
不是说freebsd-src的公共头文件,但你既然都允许整个扔进sys了也算是自己改过文件自己接手了,至少也别放在这种给FreeBSD特供的地方,还是太难看……多拆个文件吧。
其实我会注意这个,直接来自这个问题:真能确信只有那么一个模块用到了嘛?不爬历史应该是看不出来的。
假设维护这份drm2的owner很负责,那应该会发现放在这里味道不大对,而不会就放任这么稀烂的堆着;如果就是觉得这样就行放着能不管了,那么我就更得怀疑到底是不是真的有没和其它模块之间cross check过了。(从现状来看,更可能就是后者。)
至于里面合并进来的代码各种版面问题,FreeBSD 团队不可能具备 Linus 那样的脾气苛责贡献者。
那么更该自己干了。这几乎只是分割文件就能搞定,对已经了解代码的开发者不占用多少时间,不涉及具体代码功能修改也不会造成难以追溯改错了的情况,几乎就是check in进来顺手的事。
代码质量经常是个连锁问题,一个地方允许摆烂,别的地方就难说多有信心了;特别是这代码还不是一眼能看出来谁写的。(比如Linux的cifs.ko因为源码作者理解错了某个宏的写法没法直接out-of-tree build,一看有关源文件的抬头,Microsoft,哦是微软写的bug啊……这里要出幺蛾子还得另外翻历史才可能有数了。)
光这文件就不只是一个问题;比如说明明叫OS abstraction macros,仔细看看下面给的又不都是macro。
不是我要吹毛求疵,合代码的时候顺手用个更清楚的描述能咋样呢,非得留这种凭空增加读者黑人问号的槽点……
另外这种工作不是官方负责人做,别人更加不好插手。
比如说我一个路人contributor,觉得这里不对,想改得像样嘛,估计修改行数不少,要占用reviewer时间又没法实质有功能上的改善;要小改嘛不痛不痒。
结果就是不管多水的问题路人最终都会望而却步,除非你官方自己看不下去,才有可能改这种非功能bug的问题。
总之这事说大不大,但锅是有的。
要你说,这锅肯定首先是写drm的那些人的;不过我想说,既然maintainer在这方面不够push,那这锅多少也有份,而且份额会随时间自动增长。
要不单独隔个楼然后直接 at 一下给对方?
at漏了。
我现在都先引用原文再回复了,这样清楚点。
直接扔到了gist上,也懒得节约铜币了。