亚当
独立静态构造器
首先,背景.在6月月度会议上,讨论了,导入其他模块时,即使静态构造器自身没有依赖关系,也可能会进入循环依赖,执行也会因"检测到循环"错误而中止.
Adam建议引入可在静态构造器上使用的新注解,以告诉编译器它没有依赖项.然后,在关闭检查循环依赖项的单独列表中,编译器可添加进它们.
Walter说,已有了pragma(crt_constructor)编译指示的机制,指定启动时C运行时执行的函数.亚当提醒沃尔特,上次讨论过该问题.
问题是CRT构造器是在初化D运行时之前执行的,因此依赖D运行时的静态构造器都不能是CRT构造器.
沃尔特问如何实现.亚当说,实现已在D运行时中.Steve澄清说,编译器有时候可决定单独的静态构造器不参与检测循环.
不需要按指定顺序运行这些构造器,这样来分开处理.这就是亚当所指的.因为已有让编译器标记独立静态构造器的方法,只是要求用户可按独立标记构造静态器以进入同一列表的方法.
Walter说,他过去曾向人们建议,避免静态构造器上的循环检测的方法是,无需额外导入,把它们放在自己模块中.然后它们将是独立的.
亚当说这是不现实的.沃尔特说,他对亚当想法的抵制源于不愿意改变语言来做其他方式可完成的,也许不完美,但至少合理.
另外,是否可在不向语言添加新功能时就完成?
沃尔特还指出,允许这样会给语言增加不安全感.他们可能会误认为静态构造器是否有依赖项.它可能在A系统上工作,而在B系统上中断,因为无法保证它的运行顺序.
构造器排序背后的整个想法是不必了解按什么顺序运行.
至少,此功能必须隐式@system.则是否有其他方法?是否合理?
Walter接着问Adam有多少次发现程序中明显需要独立的构造器.亚当引用了他的"JNI互操作".它生成其他静态构造器,来向Java运行时注册类.
这是独立的,但因为它是由mixin完成的,所以它不能在自己的模块中启动.因此,如果可按独立标记,则可避免循环检测.
Walter想知道为什么不能在单独模块中放置mixin.除此外,Steve强调,为了避免循环检测,到处都是这些小模块会使代码更难读,并让语言更难吸引人.
在这一点上,静态构造器似乎无用.
最后,Walter说他想保留意见,直到能看到一些示例代码.
Adam提到的mixin旨在在类内实现静态构造器,而不是在模块域内,这样就无法在独立模块中放置它们.
长期版本
现在变化是除非真的必要,不会弃用.表明会继续支持旧事物.目标是不用更改及烦人的消息,所有库都可使用新的DMD编译.
他一直在稳步发布PR,来恢复一些给人们带来麻烦的弃用.计划恢复过去故意破坏的清单.想法是,一旦一个库在D中工作且已调试好,除非是重大错误,它就会继续在D中工作.
沃尔特说,这就是未来计划.它合理地解决了像GrimMaple那样的不能编译投诉,且不需要LTS.LTS在如何修复编译器中确实破坏现有代码的严重错误方面也存在问题.
这是个难题.有想要修复但又不想破坏现有代码的错误时,LTS和head版本也面临同样决定.
沃尔特认为这是合理的方法.表明可能不需要LTS版本,解决人们在编译器的每个新版本中因代码中断而遇见的问题.不想再这样做了.
我提到Walter为此添加了-wo开关,这样你想知道代码基是否在使用过时功能时,可打开它.还注意到,上周季度会议上,讨论了提供更精细控制,以便可为代码基而不是依赖项打开警告.
这样,可查看是否正在使用过时功能,而不会因依赖项的警告而使输出混乱,且这一切都是选入的.当然,仍会有弃用.
沃尔特说,想法是为了长期支持不再需要的功能.如果用户想要升级他们的包,且有时间按他们的而不是我们的时间表更新,可打开-wo开关以查看他们应该及时步进的所有事情的列表.
尼克
对-wo开关有一些评论.他说,这很好.但是,因为默认没有指示代码是否使用了过时的功能,如果人们可养成使用新开关的习惯,那就太好了.这是文化.
沃尔特同意这应该是文化的.他在(GCC)中注意到了这一点.C有些非常糟糕的特性,但GCC默认不会警告它们.
用户必须打开警告.对他来说似乎没问题,而且对GCC这似乎工作.
我注意到,如果要使-wo开关细粒度化,也应该对-d,-de和-dw同样.沃尔特问人们是否真关心它是细粒度的.
我提醒他,来自Ahrefs的Igor在一周前的季度会议上提出了该问题.约翰指出,这很重要,因为当有第三方的依赖树时,当他们做一些旧的,过时的和垃圾的事情时,你不会想进入,并改变它们.
你不会强迫他们改变.你确实想编译器告诉你代码中的部分,且不想被干扰.
沃尔特说,他想过给开关加个只针对命令行上传递的文件发出这些警告的限定器.仅针对根模块,而不是导入的.
这样,可导入其他人的库,他们不会打扰你,但你会得到关于你正在积极编译的东西的警告.这就足够了.John说,这方便构建系统整合.沃尔特说这是个非常简单的想法.
史蒂夫说,他看到的唯一问题是,如果你依赖一个也想为该库启用警告的库,你构建库,然后进入你的代码,且代码使用了该库中的模板.
是否有警告?因为你没有在命令行上传递该模块,只是导入它以使用其模板.Walter说,如果警告是来自非根模块模板的结果,你不会收到警告.
史蒂夫说,他只是想看到警告,但不能.Walter说编译器已对弃用类似做了.如,如果为同样已弃用的模板生成弃用消息,则不会看到该模板的内部弃用.只会在使用模板时看到弃用.
史蒂夫
在上一次月度会议上,他谈到了编译时关联数组初化到编译器中.运行时部分已工作了,只需要有人来处理编译器方面.
在和丹尼斯讨论之后,丹尼斯提出了替代方法的公关.
沃尔特说,他看到用户抱怨DMD已在Mac上停止工作.他知道ldc已解决它.
史蒂夫说他只是报告并测试了它,其他人已修复了它.他说这与Mac上的链接器突然对目标节布局更严格有关.
沃尔特说,DMD不在Mac上工作是不可接受的,并查询丹尼斯是否可盯着它.丹尼斯说他对Mac一无所知,史蒂夫说有很多Mac用户可帮助测试或构建.
如果需要,他提出可远程访问他的旧x86Mac.沃尔特说,他感谢这方面的帮助.
LDC的修复.
拉兹万,BetterC链接器错误
拉兹万提出了过去会议上讨论过的话题.
错误跟踪器中有一些使用BetterC时的链接器错误相关问题.一般,实例化运行时勾挂或从D运行时导入内容时,如果从运行时推测环境,及从BetterC代码使用相同参数实例化模板,则可能不会发出模板.然后得到链接器错误.
解决方法是使用-allinst编译.Razvan说他已提出了一个拉取请求来解决该问题,这样现在使用-betterc编译就隐式表明有-allinst.但会导致一些项目的编译速度变慢.公关,马丁这没有问题,但拉兹万想知道会议中是否有人觉得不好.
Walter问为什么不能告诉人们,把-betterc和-allinst一起使用.Razvan说,即使这样,人们也不会知道这件事,所以会以同样没有信息的链接器错误结束.
沃尔特承认这点,但他说如果把两者结合起来,则有一天人们会问没有allinst的-betterc.
Steve建议可有一个-allinst版本,允许指定应该只实例化指定模块的模板.如根模块,或核心等.沃尔特说这是有可能的.
Walter另外建议不要让D运行时实例化自己的模板.让它使用不同模板.然后编译器会认为它们没有被D运行时使用.
它应该只是少数模板.罗伯特认为这不行.史蒂夫说这不仅是运行时.模块都可能这样,即使是那些不直接导入的模块.
如,模块不是公共API的一部分,但在私有内部API中,它恰好实例化模板.很难回答何时实例化及编译器决定不发出它的原因.
沃尔特说,拉兹万应该继续他的方法.他想有个更好的方法,但这是目前唯一的方法.
Steve说,公平地说,BetterC是指定不链接运行时的开关.它也可说它不会从那里实例化模板,因为它没有与它链接.
Dennis指出,BetterC用户想要越来越多的东西与BetterC一起工作.可告诉他们,它应该是为了用现有的C整合项目新代码及一些利基微架构,但他们仍只是想在BetterC中可以比较数组.
Walter认为他已修复串比较,所以现在应该可工作了.
Razvan说:在BetterC中,编译器只为运行时勾挂假设-allinst.这有效,但似乎有点笨拙.
沃尔特开玩笑说,-allinst自身也有点笨拙.然后他说拉兹万的最初想法是正确的,拉兹万应该继续他的公关.
丹尼斯
安全错误和-wo
丹尼斯首先指出,沃尔特一直在-wo开关后面移动安全错误.他发现这有点麻烦,因为安全错误并没有过时.告诉用户,如果想要适当内存安全,必须启用过时警告检查听起来很混乱.
1
2
丹尼斯说,他知道当前默认弃用泛滥很烦人,但如果想默认达到DIP1000,它需要.否则,为什么仍要DIP1000和内存安全?
Walter说,在第一个链接中,有一个来自dlang-tour/core的BuildKite错误,这是关于弃用域消息的暴风雪.
不必打开-preview=dip1000.它们默认.问题是,人们现有的工作代码,他们添加了域,现在已破坏了他们所有的代码.
丹尼斯说它没有坏,这只是个弃用信息.沃尔特说,dlang-tour已坏了好几个星期,还没有修复.这正是-wo要解决:人们使用的库破坏了,但没人愿意修复库.
丹尼斯说它并没有因此而破坏.这只是个警告.因为超链接不管用,它才破坏了.Walter说,他看到的只是赋值域参数给非域参数的各种消息.
丹尼斯说,这并没有破坏构建.破坏构建的是一个未正确解析md链接PR.这就是它失败的原因.
沃尔特说他明白了.重点仍是仍存在弃用消息暴风雪问题,并说未来不会编译此代码.丹尼斯说这是事实,并问是否不想步进DIP1000.
Walter回答说,确实想继续使用DIP1000,但也想编译较旧的代码.他强调,他了解丹尼斯的来历,两三个月前就会完全同意他的观点.
但是他现在认为,即使正确,现在只是破坏了人们使用域的现有代码.是的,他想默认移动到DIP1000,但他不想破坏现有代码.这就是-wo的目的.
编译器会接受在现代D中不可接受的代码,因此仍可用旧代码.在曾经工作并且正确的旧库上,没人愿意看到满屏弃用消息或彻底错误.
只因为编译器想要更严格标准.沃尔特认为需要放宽这些标准.
史蒂夫说,弃用消息暴风雪的部分问题是,其中很多都是很简单的.如,此模板现在按@safe推导,但默认启用DIP1000后,它按@system推导.
因此,可能并没有真正从安全代码调用它.因此,即使稍后会按@system推导,但不会影响项目的编译.
Walter谈到了推导安全的实现细节,然后说人们使用域并期望它起作用.它管用了.只是随着D的现代版本和想要前进的方向,这是个问题.
但是为了支持较旧代码,需要行为方式与一直默认的相同,以便使用这些构造时不会干扰不安全.这就是重点,停止破坏用户代码.
John说,还有D无法构建,或人们编写D无法创建封装代码.考虑你未来要继续使用的C库.C库喜欢公开相对有限的接口,但内部,可做各种疯狂的事情.
但是你可相信该接口,因为它已经过调试.因此,对它打开新的警告标志很烦人.但是在D中,模板和mixin方向不同,而内省更全面.
人们可构建一个库,调试它,且用户未来可信任它.虽然他支持-wo开关,但这稍微削弱了它的论据.
如,如果依赖项未遵循DIP1000的规则,则表明你可能未遵循规则.如果传递类型给模板,然后相应再传递给另一个模板等,则很容易这样.
沃尔特说他理解约翰的意思.Walter说-wo是为那些对正在编写代码有更高标准人准备的.如果使用它,编译器会告诉你你正在导入库的所有错误,你可决定如何处理它.
是否要使用10年前的该库,即使编译器也无法保证它是内存安全的,让用户做出选择.约翰承认只能这样了.
Walter指出,不这样做时,C编译器会为你隐式声明一个函数.这太可怕了,因为它默认带某些参数和返回值.
所有这些都是隐式的,即使它可能只是拼写错误.编译器仍会毫无怨言地编译它,因为人们有很多他们不想修复的旧C代码,但他们确实想按过去方式来编译并工作.D需要同样.
我仍在试了解当DIP1000成为默认值时会怎样.他正在恢复其他弃用,并放在-wo的后面,因为它们是删除.
而没有删除域.这是过渡,警告DIP1000为默认时,行为变化了.真的默认时,这突然是个错误,会破坏所有旧代码.
要把DIP1000放在-wo后面吗?
沃尔特说他没有看到其他方法.它会放在-wo上.我说那样,就不是默认的.约翰说这听起来很像语言版本,我同意.沃尔特说,想要安全的人会启用-wo,而那些不想要安全的人不会.
Dennis说目前还可用-preview和-revert.他觉得现在很多事情只是改变消息颜色,改变是否是默认的.
如果来回这样做,它只会一团糟.首先,你需要-preview=dip1000,然后你需要-wo,然后当人们想要默认的内存安全时会怎样?我同意在没有硬边界时,很难默认获得DIP1000.正如约翰所说,需要版本等,因为变化简直是惊天动地的.
John问为什么假设关于过时功能的警告应该选入来打开它们,而不是选出以让编译器闭嘴.我说这是因为收到了很多关于弃用消息的抱怨,现在,你必须选出.
John问是否考虑过这是否与它们是弃用消息的事实有关,所以编译器告诉你"当心,必须改变它,否则会破坏你的代码",而不是"嘿,这里有一堆错误方式,但你可忽略它们".
因为弃用消息,是你知道不应忽略它.而未来会破坏.
马丁一直在抱怨Symmetry代码基的域弃用问题,因为在Symmetry代码外的依赖项中有很多域.
这是阻止升级到较新编译器版本的原因之一.丹尼斯说,这可通过过滤模式为弃用和警告开关来解决.
约翰说,有时候这就足够了.
Walter说他记得Sociomantic花了大约10年的时间来从D1升级代码.他们投入大量精力编译旧代码.
他不想再这样了.如果无法升级到最新编译器,则不必强迫.
丹尼斯说这就是-preview和-revert的用法.
我提醒大家,并不是完全丢掉弃用.域是个应该保留它的完美示例.只要有像-d此类过滤弃用开关,则用户可为自己的代码打开弃用,而对特定包关闭它.
Mathias说,Sociomantic之所以在D1上停留的时间最长,并不是因为暴风雪般弃用,而是因为从D1到D2没有明确的升级路径.
这只是个艰难突破.他们必须过渡.他们确实移植Tango到D2,因此不得不从运行时中分离出Tango来.
他们必须编译D1和D2代码.
沃尔特说他不想再有类似事情发生.
弃用域当然是侵入性的,但许多其他弃用不是.他过去曾建议分组弃用,如每两年只发布一个弃用版本.
但冻结语言只是在消亡.甚至Rust每年也会更改一次语言.
Walter说他被告知Rust仍会编译旧代码.我说理解是Rust有"时代"的,想法是,需要升级的新功能集之间有明确的界限,但仍可编译旧代码这里.
我说,需要定义并记录如何处理弃用,如何处理过时功能及如何处理像DIP1000等巨大突破性转换的清晰路径.
马蒂亚斯说,这已很清楚了.弃用持续十个版本.一些弃用持续时间更长.如,body弃用是二十个版本,因为它非常有影响力.
但从不硬性破坏,或至少非常努力避免它.因此当决定需要用DIP1000前移时,Dennis做了默认DIP1000打开时,把看到的未来错误转换为弃用消息的有影响力的工作.
因为否则,无法默认启用DIP1000.如果不允许这样,则不能默认打开预览开关.
我说弃用域只是过渡,需要为该类事情制定策略,以便可知道在做什么.
拉兹万说,最近不弃用不是正确的方向.是的,发出太多弃用消息不好,但没人说再也不弃用.
弃用过程是正确的.主要是弃用了太多,但该过程自身是有效的.也许应该限制给定时间段内弃用次数.因为如果冻结语言,这会是一个大问题.
沃尔特说这些都是好点,但他强调并不打算永远不弃用.想做的是逐个查看,并决定是否真的需要弃用它.
如,消除逗号式的原理,是可有合理元组语法.弃用它,没关系.但是还有其他,比如body关键字,弃用了它,转而支持do.
但表明,可在语言中按环境关键字保留它,且效果很好.即使不是语言的官方部分,也可永远支持它.然后-wo可告诉你,嘿,为什么不改变代码中的body为do?或用分号弃用空语句.
在这方面破坏代码不是好主意.把它留在里面不是问题,所以他有个PR来重新启用它.唯一困难是DIP1000.
我说我完全支持他恢复所有这些,但恢复域是错误的.沃尔特说,还应该考虑到DIP1000还不完美.它仍有错误.
是否真想在解决所有错误前开始弃用它,且可自信地说应该在所有代码上使用DIP1000?也许当DIP1000更完美时,可重新审视这一点.
与此同时,他想继续两个把域的东西放在-wo后的PR.与域构造器一样.他发现必须这样做时,知道这有破坏性,因此他预先为DMD中的所有构造器添加了域.
但是为用户启用此功能对他们来说是非常有破坏性的.
丹尼斯说他明白了.他不介意说有点预先,暂时关闭弃用,更好状态时重新打开它们.问题是把它们放在-wo后面.
这没用,如果根据DMD版本及使用标志,收到警告和弃用或错误,只会在版本间切换状态时造成混乱.
所以宁愿暂时禁止弃用,而不是放在-wo后面,也许在它更好状态时启用它.否则只会收到用户对混乱开关的抱怨.
史蒂夫说,他一直在通过构建vibe.d来处理域相关弃用消息.他看到消息说因为调用了标准库深处的另一个函数,不能叫该函数安全.这不应该.
在标准库支持它前,不应启用它.沃尔特同意了.他说标准库应该与DIP1000完美配合.这很明显.
因此,问题是,是否只是像Dennis建议的那样暂时禁止域弃用消息,还是像Walter想要的那样把它们放在-wo后面.
史蒂文同意应该禁止.沃尔特说,把它们放在-wo后面是禁止它们的好方法.丹尼斯不同意,说这没有意义,因为它不是过时的功能.
沃尔特说丹尼斯在语义上是正确的,但务实地,这很好.丹尼斯说,用户过去曾抱怨开关做其他古怪的事情.
空初化布尔值
丹尼斯还没有说完.他的最后一项是他提交的PR这里,该PR在系统变量预览下,按@system标记,布尔值或包含布尔值的空初化.
如果使用bool索引,编译器喜欢避免检查边界,因为它知道它只能是0或1,但是当按void初化bool时,可能会比这更大,且可能会破坏内存.
他说,有一些不同意见.一个是每个void初化都要@system,但这是个更大的突破性变化,不大会这样.
或按有不安全位模式类型对待bool.沃尔特说他要考虑一下,并感谢丹尼斯提出来.
Iain说,在GDC方面,直到最近,都按1掩码所有读布尔.他已撤回了它,现在仅当是联内部某个字段的读取布尔时,才这样.
Dennis同意这是DMD有时候的另一个选择,但它的性能较差.如果想要高性能且安全的布尔值,最好处理void初化.伊恩说,性能也是他撤回它的原因.
沃尔特重复说他必须考虑一下.
沃尔特
除此外,他还专注于错误修复,浏览弃用列表,并研究在DMD后端添加对ENDBR指令的支持.
我问Walter,他在支持DLL和文档方面是否有进展?.在六月的月度会议上,他说在调查编译器中DLL支持的当前状态,并写了一篇文章来记录他的发现,并试完成缺少的内容.
沃尔特说,他有个与DLL相关的停滞中的公关,所以转向了其他事情.但是,他在网站上发布了一篇文章,他打算在实现上可有更多进展后扩展.