注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天地不仁,以万物为Googol!

天行有常,不以物喜,不以己悲……

 
 
 

日志

 
 

C++ 0x决定“移除Concepts”  

2009-07-31 16:09:49|  分类: 翻译 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
译自:http://www.ddj.com/cpp/218600111?pgno=1

Bjarne Stroustrup

2009年7月在德国Frankfurt召开的会议上,C++标准委员会通过投票决定从C++0x中移除Concepts。那些已经为Concepts工作了很多年的人,以及知道Concept潜在能力的人,听到这个消息会感到十分失望,不过,这个决定不会影响大部分C++程序员。与C++98相比,C++0x在现实的程序世界里依然更有表现力和效率。委员会移除Concepts是为了控制风险和保证进度。也许5年后会提供一个改进后更强大的Concepts。本文记录了移除Concept的原因,简要记录了导致委员会这么做的争论和风险,提供一些参考给喜欢研究Concepts的人,并且指出(与广为流传的谣言相反)C++的”天不会蹋“。

没有Concepts的C++0x

2009年7月在Frankfurt召开的ISO C++标准会议(WG21)上,用来限定模板参数需求的机制Concepts被标记为“去除“(更直接的说是“淘汰“)。就是说,Concepts不会在C++0x以及标准库里出现。这件事——在我看来——是C++一次重大的倒退,但并不是灾难;如果不这样做,可能会更糟。

我已经围绕Concepts本身工作了七年,而之前为了得到这个解决方案,花了更长的时间。其他围绕Concepts工作的人也花了差不多同样长的时间。比如(按时间排序):
不用说,我和其他人都很失望。其他选择会更糟的事实很让人心寒,而且我也没法给出快速简单的补救措施。

需要注意的是,C++0x对特性的改进不会对大部分程序员和直接使用者灶成影响。有了对并行编程的支持,更好的标准库,以及其他会使使用者写出(在效率和维护上)更好代码的改进,C++0x依旧比C++98更有表现力。特别是,所有我曾经给出的C++0x的例子(比如,在ACM HOPL-III上的向着现实并服务现实而演进的语言:C++ 1991-2006里的例子),只要不包含关键字“concepts“和”requires“,都不受影响。也可以参考我维护的C++0x FAQ。一些人甚至很欢迎这个改动,因为这使C++变得比他们期盼的还简单。

concepts曾经是为了让模板的使用有更好的理论基础而提出的重要新特性,可以使标准库的定义更严谨,而且也是让泛型编程更容易让大众使用的重要部分。不过现在,只能在没有语言支持的情况下使用concepts。在我看来,最理想的未来是,今后五年有更好的概念来代替concepts。这需要一些人为此努力工作(但不是“由委员会来设计”)。

发生了什么?

concepts,在经过过去多年的发展并于2008年接受进入C++0x工作论文后,引入了很多技术上的妥协(这些妥协是合乎常理且必须的。)实验性的实现已经足够测试concepts化的标准库,但是还没达到能成为产品的质量。质量问题令一些人很担心,但是我个人认为这些测试已经足够证明concepts本身了。

我关心的是如何设计Concepts,特别是concepts在平均水平的程序员中的易用性。这些心得会在一些委员会成员中分享。concepts的既定目标是让广大的程序员更容易使用泛型编程[BS&GDR2003],但在我看来,这只是我目标的一部分:不仅仅让泛型编程更易用,concepts将会(只)成为专家手里另一个有力的工具。在过去半年左右的时间里,我从用户的角度重新审视了C++0x,我担心即便是使用concepts化的库,依旧会给程序员增加额外负担。我觉得目前concepts的设计和在标准库中的应用,并没有恰当体现出这些年在concepts上的经验。

几个月后,Alisdair Meredith(一个来自UK的富有洞察力的委员)和Howard Hinnant(标准库工作组的头头)问了一些问题,这些问题是关于谁应该直接使用concepts的哪个特性,以及如何使用。这导致了一场关于易用性的讨论,有很多人发表了自己的看法和观点。最终,在经过复杂的讨论后,我公开了我的结论[BS2009]。

简而言之,我的观点是:
  • concepts目前的定义难于使用,而且很容易导致误用concepts,误用模板,所以也许还不足以被C++0x接纳。
  • 一组小的简化可以在现有的C++0x进度表上,提供足够使用(good-enough-to-ship)的concepts,或者可能只遗漏一些小功能。
这个证据实在太强了(应该指从C++0x移出concepts的证据)。请记住,委员会的讨论一般都是很友善的,而且我们的目的是达成一致,因此会尽量避免直接与不同意见对峙。不幸的是,这场决定未来的(内部)讨论规模庞大(数以百计的详杂信息)且杂乱不堪。我们无法就具体讨论什么问题(如果确实有问题的话)和如何讨论达成一致。这使我在Frankfurt展示了几个其他的解决方案:
  • “解决并发布”

    • 遗留工作:移除显式“concepts“,加入显式精化(explicit refinement),加入“concepts“/类型匹配,处理“concepts“映射范围的问题。
    • 风险:没有实现,描述复杂。
    • 时间表:没有改变,或者再有一个会议。

  • "约定并发布"

    • 遗留工作:约定(核心和标准库)
    • 风险:旧模板的问题依旧存在,让“革新”社区失望(“消耗了7年的工作“)
    • 时间表:在concepts上再有五年的工作(需要全部重新设计)或者没有时间表。

  • "维持现状"

    • 遗留工作:细节。
    • 风险:不能接受的编程模型,复杂的描述(另外的观点:没有)
    • 时间表:没改变
我和一些人更喜欢第一种方案(“解决并发布”),并认为这个方案是可行的。不过,委员会里大部分人选择了第二种方案("约定并发布" ,改叫“移除”)。在我看来,这两种方案都好于第三种(“维持现状”)。“Concepts“的支持者里有一部分人也投票反对在C++0x里加入concepts,我对这类投票的解释是,整个加入concepts这个想法似乎会引起一些争论,而这些争论会影响到C++0x的进度(在我看来,这些对concepts的职责是不公平的),而且有些人对concepts根本没有兴趣。有鉴于此,”解决并发布“不是一个现实的选择。实际上,所有支承concepts的特性描述,都被“推迟”或者“终止”了。我警告过如果现在移除concepts,必然要等很久才能重新继续探讨这个特性,因为不再有进度的压力,基本上需要重新评估所有设计。

很令人惊讶的是(可能是吧),在Frankfurt上没有任何关于concepts的技术演讲和讨论。讨论都集中在计划时间,而且我印象里所有投票都优先考虑的是时间因素。

不过并不能批评委员会过于谨慎。这并不是“Bjarne与委员会对拼“,讨论的目的是试图平衡很多重要的事情。我和其他一些人对没有机会“解决并发布“concepts感到失望,但C++并不是一门学院性质的实验语言。除非其他成员认为新特性对已有产品代码产生破坏的风险很低,不然他们一定会反对。总体上说,委员会对数亿行代码负责。比如,如果concepts得不到C++0x的支持,或者已有concepts但长时间依旧使用无约束的模板,会导致C++社区分裂成很多子社区。因此,一个不完善的concepts比不提供concepts更糟糕。如果要在这两个间选择,我也会选择移除concepts。我宁愿选择受挫,而不是灾难。

技术问题

concepts没有解决的问题主要是如何区别显式映射和隐式映射。(参见[BS2009]):

  1. 当有concepts的限定需求时,一个类型需要匹配concepts,是使用自动类型匹配(比如,一个提供了带有适当参数的+-*/的类型X,是否应当自动匹配到需求常见运算符的concept C?),还是需要一个额外的显式声明(一个从X到C的concept映射)来确定具体的匹配?(我的答案:在绝大部分情况里使用自动匹配。)
  2. 是否应该在使用自动concepts和显式concepts间提供某种选择?是否设计者可以强制所有使用者遵从他的选择?(我的答案:所有的concepts都应该自动匹配)
  3. 如果一个类型X提供了成员函数X::begin(),这个成员应该自动匹配到一个需求begin(T)的concept C<T>,还是需要用户提供一个从T到C的concept映射?一个例子是std::vector和std::Range。(我的答案是:应该自动匹配)
对“在Frankfurt维持现状“的回应,都和我的建议相左。看来我必须简化我的解释并且提供足够的细节和理由。

我不能把整个讨论都重复一遍,不过我的结论是:在“维持现状”的设计里,concepts映射有两个作用:
  • 通过增加/映射某些属性,把类型映射到concepts,
  • 判断一个类型是否能匹配一个concept。
不过,第二种情况在某些人眼里更重要,而不是把它当作某种不合适的少见的需求。当两个concepts在语义上不同时,需要的不是判断一个类型可以匹配其中一个而不能匹配其他(这个——在最好的情况下,也只是一个变通方案——其实是对基本问题的一种间接且精心的攻击),而是某个类型是否满足某个concepts的语义而不满足其他的语义(满足成为一个axiom(s)的语义而不是其他的语义)。

举个例子,STL的input迭代器和forward迭代器在语法上有个关键的差异:你可以从一个forward迭代器开始做两次遍历,而input迭代器却不行。比如,在需要多次遍历的算法里最好不要使用流迭代器。“维持现状”的解决方法是强制每个使用者声明哪个类型匹配到forward迭代器,哪个类型匹配到input迭代器。我希望增加的内容:当(且仅当)你的类型想表达的语法对两个concept来说都是不自然的,而编译器无法判断哪个concepts更适合你的类型时,你必须明确表达你希望的语法:比如,“我的类型支持多次遍历语法”。有人可能说:“当你所拥有的只是concept映射时,所有东西看起来都需要一个类型/concept断言。“

在Frankfurt的会议上,我总结:

  • 为什么我们想要“concepts“?

    • 用来明确模板参数对类型的需求

      • 明确的文档
      • 更好的错误信息
      • 重载
不同的人有不同的看法和侧重。无论如何,从高层次上说,这个回答可能有点不够清晰——但是不会引起太大的争论。所有合理的concept半成品设计都提供了上述特性。

  • 人们关注什么?

    • 可编程性
    • 正式规范的复杂性
    • 编译时间
    • 运行时间
我个人更关心可编程性(易用性,通用性,易学性,可扩展性),正式规范的复杂性(40页的标准文本)是第二位的。其他人更关心编译时间和运行时间。不过,我认为实验性的实现(ConceptGCC [Gregor2006])表明,受约束的模板(使用concepts)和无约束模板的运行速度一样快,甚至更快些。ConceptsGCC本身真是够慢的,但我想这并不重要。当其验证完所有想法后,我们就可以摆脱现在的困境。最简单的说,现在的困境是:
  • “不要在没有商业化的实现前进行标准化”
  • “主流厂商不会在没有标准的情况下实现某个特性”
不论怎样,细节设计和实验性的实现间,必须达成某种方式的妥协。

我对concepts的原则是:

  • 鸭子类型(典故:看上去像鸭子,走起来像鸭子,还会“嘎嘎”叫的那个就可以当作鸭子)

    • 让模板在泛型编程中成功的关键(与其他特性对比,比如带接口的面相对象)

  • 可替代性

    • 在没有比“保证”更强的先决条件下,决不调用某个函数。

  • “偶然匹配“只是很小的问题"

    • 决不在前100个需要解决的问题里

我在Frankfurt之前的工作论文里展示的对concepts的“微小修正”:

  • concepts是隐式/自动的

    • 使鸭式类型成为规则

  • 明确细化

    • 解决可替代性的问题

  • 一般的concept映射可见性

    • 最小化“实现泄漏“(应该是指某个编译单元的映射会在别的编译单元里起意外作用)

  • 简单的类型/concept匹配

    • 将vector看成一个range,而不需要多余的concept映射

更多的细节,参见[BS2009]。


没有C++0x了,C++1x长存

即便移除了concepts,下一代C++标准依然会推迟。坏消息是,不会有C++0x了(除非你把C++03这种修正标准算进来)。我们只能等C++1x,并且期盼x是个小数字。好消息是,C++1x已经确认了所有特性(除非某个国际标准组织强烈坚持要在正式标准里加入某些特性)。剩下的,就是大量解决重大技术问题和意见的工作了。

特性列表和讨论可以在我的C++0x问答里找到。这里给出一部分:

还有库:


即便没有concepts,与C++98相比,C++1x也会有很大进步,尤其是当你认为这些特性(还有其他的)是为了协调最大化表达能力和灵活性而设计的。我希望我们能在大概5年后的C++修订版本中看到concepts。也许我们可以把那个版本称作C++1y甚至是C++y!

后记:

总之,当年震撼人心的concepts就没了。目前来看C++确实越来越臃肿而缓慢(这个不是说速度,而是指标准),不知道C++++(C#不算!)啥时能出现。或许虚拟机平台+部分编译才是真的出路?LLVM?
  评论这张
 
阅读(2268)| 评论(5)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017