长度大于 1 的条件



从历史上看,R 语言允许 ifwhile 语句中的条件为向量(长度大于 1)。使用第一个元素,但忽略其余元素,自 2002 年 11 月起还会显示警告(由 Brian Ripley 添加)。根据直觉,此类情况通常是由编程错误引起的,因此在 2017 年 3 月添加了一个选项,可以选择发出运行时错误信号(该补丁由 Martin Maechler 编写,由 Henrik Bengtsson 在 R-devel 邮件列表上提出建议后 ping)。虽然从技术上看这似乎是一个微不足道的更改,但此博客的目的是传达,将此类警告无条件更改为错误需要付出巨大的努力,因为存在大量现有代码(并且尚未进行更改,但我们可能即将完成)。

第一步是查看由于此类更改,有多少来自 CRAN 和 Bioconductor 的包将开始失败。由于包的数量,这本身需要一些非平凡的基础设施,但我们已经为 R 更改的常规和不规则测试准备好了这些基础设施。2017 年 3 月,有 154 个包在 CRAN 上失败,36 个在 BIOC 上失败。调试一些失败并没有对直觉产生任何疑问,即此类条件通常确实是编程错误(即使存在例如故意演示长度大于 1 的条件的行为的小插曲)。不过,让如此多的包失败是不可能的(而且,如果要移除/存档如此多的包,其影响会因其依赖关系而更大)。此外,原则上,可能存在合法依赖于此行为的正确代码,而我们只会破坏该代码。此外,即使这些是编程错误,它们也不总是严重到足以移除包(例如,我看到的情况只会影响测试,只会对不寻常的设置产生影响,等等)。因此,虽然运行所有这些实验、查看一些结果以及使用一些必要的诊断实现运行时检查(此时仅在我的实验分支中,R-devel 只有可选的运行时错误)花费了几天时间,但这仅仅是开始。剩下的真正工作留给了 CRAN 和 BIOC 存储库的维护者,以便联系已识别的包的包维护者,进而让包维护者修复其代码。

为此,我的实验诊断已经包含了一些检查,以查看带有错误条件的 if/while 语句来自哪个包,因为它并不总是正在检查的包。这需要稍微污染代码(在快速路径上传递参数,而这些参数仅在慢速路径上进行诊断时需要),并编写一些脚本来处理存储库维护者的结果,但与存储库维护者剩下的工作相比,总的工作量不大。

8 个月后运行相同的检查,我们有 179 个失败的 CRAN 包和 40 个 BIOC,因此比以前更多,尽管存储库维护者在一次性检查后与包作者进行了沟通。显然,我们离能够做出改变还很遥远。下一步是在 CRAN 入站检查中启用错误,以至少防止问题变得更大。此举已经要求将更复杂的诊断代码集成到 R-devel 中,以便仅当包的代码中(而不是其他依赖项中,但由测试触发)存在不正确的条件时,包才会失败其测试。这会错过一些错误,但要求包维护者说服其依赖包的维护者应用修复程序是不合理的。

又过了 3 个月(2018 年 4 月),我再次检查,失败的包总数从 219 个略微下降到 142 个,因此 CRAN 团队(反过来可能是包维护者,但我没有数据说明修复了多少包,归档了多少包)的辛勤工作似乎开始有了回报。

最后,又过了 6 个月(2018 年 10 月),我们有 34 个失败的 CRAN 包和 32 个失败的 BIOC 3.7 包。此轮测试的结果位于 https://github.com/kalibera/rifcond。CRAN 的几乎所有失败和 BIOC 的几个失败已经针对在测试期间使用错误条件的 if/while 语句运行依赖项的包,因此下一步的逻辑步骤也是针对这些错误采取行动。因此,R-devel 中的诊断代码已进一步扩展,以便在出现错误时选择性地打印(非常)详细的诊断信息。它还已扩展为无条件中止 R(我们已经看到过几个案例,其中检测到错误条件的正常 R 错误已被 R 代码捕获)。