`
hqs7636
  • 浏览: 216272 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

三访安德烈Alexandrescu(第2部)

阅读更多
Google翻译哦
面试------> 应翻成 访谈

这部分大约为D编程语言面试2认为埃里克Niebler和Andrei Alexandrescu在讨论中深切地关注结构体与班,复制语义,右值引用的困难,垃圾收集复杂,和安德烈的偶尔失败作为旗手服务政策为基础的设计。

See Part 1 of this interview.见第1部分的采访。

Eric: D supports both value semantics (structs) and reference semantics (classes).埃里克:D支持两个值语义(结构)和参考语义(班)。 One surprising thing about D's struct/class dichotomy is that the same syntax, t = u, does such radically different things for the two of them: for structs, it copies; for classes, it aliases.一对D的结构/类二分法令人惊讶的是,同样的语法,吨= u时,会有这样截然不同的事情他们两个:为结构体,它的副本;上课,它的别名。 Does it hurt generic code and readability in general not to know whether t = u creates independent copies or aliases?会不会痛一般不知道是否T = ü创建独立的副本或别名通用代码和可读性?

Andrei: Ha—good question!安德烈:哈,好问题! I'd actually rephrase your insight a bit.我其实是修改你的洞察力1位。 On the face of it, indeed, "copying" a class variable is really copying a reference, just like in Java, C#, and many other languages, whereas copying a struct variable in D copies the actual value—that is, each and every field.在表面看来,的确,“复制”一类的变量是真的复制,就像在Java,C#和许多其他语言的一个参考,而复制一个在D副本的实际价值,也就是结构变量的每场。 But this apparent dichotomy between reference versus value semantics is really a harmonious relationship between reference and custom semantics.但是,这与参考值之间的语义对立确实是一个明显的参考和自定义语义之间的和谐关系。

Structs are very flexible; they can be made to have reference semantics, value semantics, and everything in between.结构是非常灵活,他们可以向有参考语义,语义的价值,以及所有介于两者之间。 Consider:考虑:

// A bona fide D class / /一个真正的D级
class X {类X(
private int x;私人诠释十;
int method(int y) { return x + y; }诠释方法(诠释y)的(返回X + Y键;)
} )

// A struct with reference semantics / /一个参考语义结构
struct S {结构S(
private X payload;私人X有效载荷;
... ...
} )

In the case above, S has de jure value semantics but de facto reference semantics: Copying S objects around really copies references to X objects.在上面的情况,S有法律上的价值,但事实上的参考语义语义:大约真的副本复制对象的引用到X析对知识产权客体。 This is because S has exactly one field, and that field has reference semantics.这是因为S有精确的一个领域,这个领域有参考语义。

Seen from that perspective, no conflict exists.从这一角度看,没有冲突存在。 For some generic algorithm, you specify the expected meaning of each operation (notably that of copying objects around).对于一些通用的算法,您指定的每个操作(预计意思是复制的对象主要是周围)。 If you clearly can't expect to work with reference semantics, it's very easy to eliminate classes from the matched subset of the type universe:如果你显然不能期望工作参考语义,这很容易消除该类型的宇宙匹配的子集类:

void willNotWorkForClasses(T)(T value) if (!is(T == class)) {无效willNotWorkForClasses(T)的(T值)如果(!是(Ŧ ==类))(
... ...
} )

The if clause introduces a so-called template constraint.如果引进的第一个所谓的模板约束。 I proposed template constraints about a year ago as a lightweight alternative to concepts, and now I'm happy I did; they've solved a ton of difficult problems very elegantly.我建议模板的限制约一年前作为一个轻量级的替代品的概念,现在我很高兴我没有,他们已经解决了难题,非常优雅吨。

To answer your question: Classes simplify things a fair amount, but structs offer a lot of semantic flexibility (not to mention efficiency).为了回答你的问题:一类简化的东西相当多,但结构体提供了一个灵活的语义(更不用提效率)很多。 I see their coexistence not as a source of conflict and confusion, but instead as complementary harmony.我看到他们的相处没有冲突和混乱的根源,而是互为补充的和谐。 You must have both in a multi-paradigm language.您必须同时在多范式语言。

Eric: With Mojo in C++[1], you addressed the issue of value semantics with efficient move.艾瑞克:与Mojo在C + + [1],你给高效动议值语义的问题。 C++0x puts move right in the core of the language with rvalue references.的C + +0 x把在右值引用与语言的核心向右移动。 D doesn't have them. D不拥有核*武*器。 What alternatives does it offer?它提供什么办法?

Andrei: The copy semantics as defined by C++98 aged really badly.安德烈:复制语义由年龄实在太差的C + +98定义。 I'm not saying that as a criticism—it's a very difficult problem!我不是说,作为一个批评,这是一个非常棘手的问题! Mojo and other similar mini-frameworks are only palliative solutions to this nuisance. Mojo网站和其他类似的小框架,以解决这个困扰只姑息。 Most other languages chose to stay away from allowing user-definable copy semantics.大多数其他语言的选择远离允许用户自定义的拷贝语义了。 Case in point: D version 1 chose to allow structs with (shallow) value semantics but not with hookable copying, just like C#.案例分析:D版一选择,让结构体与(浅)值语义而不是仅仅复制与hookable如C#。

When we designed D version 2, we were extremely careful to mark a net improvement from C++ in terms of copy semantics.当我们设计的D版2中,我们都非常谨慎,以纪念从C + +净改善的复制语义条件。 We came up with a very simple and effective system:我们想出了一个非常简单和有效的制度:

1. 1。 All objects are "relocatable"; that is, they can be moved through memory by using bitwise copying, à la memcpy.所有的对象是“浮动”,即他们可以通过移动存储器使用按位拷贝,这有点像memcpy的。
2. 2。 As a consequence of (1), the compiler never copies rvalues—it just moves them.作为一个结果(1),编译器永远不会复制rvalues,只是他们采取行动。
3. 3。 Returning a stack-allocated parameter or a value parameter from a function is a move, not a copy.从一个函数返回堆栈分配参数或参数值是一个移动,而不是一个副本。
4. 4。 The library provides a simple convenience function move() such that move(value) reads value destructively and returns it as a (moved) rvalue.该库提供了一种简单方便的功能移动()使得移动(值)破坏性读取值并返回它作为一个(移动)右值。
5. 5。 A struct can define a special hook function called this(this), also known as the postblit function, that the compiler calls against the target immediately after creating a bitwise duplicate of an object.一个结构可以定义一个特殊的钩子函数调用这(这),也被称为postblit功能,即对目标的编译器调用后,立即建立一个按位复制的对象。 The postblit scales better than the C++ copy constructors because you can add new fields without needing to adjust the postblit.该postblit规模要比C + +拷贝构造函数,因为你可以添加,而无需调整postblit的新领域。

This system obviates the need for the devilishly difficult copy elision rules in C++ (one of my least favorite parts in that language's definition), and of course doesn't incur the hit of a new type constructor with its own rules and quirks, as rvalue references are.该系统省却为过分地难以复制在C + +(我最不喜欢这种语言的定义部分之一省略规则的必要性),当然不会招致有自己的规则和怪癖作为右值,新型构造击中引用。 And, boy, are they quirky!而且,孩子,他们是古怪! Did you know that… bah, I'll save that for another day.你知道...呸,我会保存,为新的一天。

Again, this is not to criticize; I followed the rvalue proposal for C++ quite closely, and at one point I suggested a simpler scheme that Howard Hinnant proved to me would have broken compatibility (which is a no-no).同样,这不是批评,我遵循了对C + +右值的建议相当密切,在有一点我提出了一个简单的计划,霍华德欣南特证明我已完全破裂指数(这是一个不无)。 To the credit of their creators, rvalue references achieve most of what they need to do, within an extraordinarily constrained setup.对于他们的创造者的信用,右值引用实现他们最需要做的,在一个非常限制设置。 This trick reminds me of a scene in the movie Apollo 13, in which astronauts must build a sui generis air filter out of a plastic bag, a hose, a sock, and whatnot—except that, in the case of rvalues, only some unmentionables were available.这一招想起在电影阿波罗13号中,宇航员必须建立一个专门的空气过滤掉一个塑料袋,一个软管,袜子,以及诸如此类的东西,只不过,在rvalues情况下,只有一些场景我unmentionables还是存在的。

Anyway, getting back to D, the approach has a few more details, but the five points above convey the gist.不管怎样,回到至D,该方法有一些细节,但以上五点传达精神。 The system works pretty darned well, is efficient, and requires no intervention (or only minimal intervention) from the user.这个制度运作非常该死的好,效率高,无需进行干预(或只有极少的干预)的用户。 The only disadvantage is ruling out internal pointers.唯一的缺点是排除了内部指针。 But exceedingly few objects point inside themselves, and why hurt most for the doubtful benefit of a few?但极其几个对象点内自己,为什么受伤的几个疑问最大的受益者?

Stacking D's uniform bitblitting of objects plus the postblit hook against C++'s copy-elision rules and rvalue references, I think D is making significant progress.堆叠德的制服bitblitting对象加上抗C + +的副本,省略的规则和右值引用postblit挂钩,我认为D是取得重大进展。

Eric: Rightly or wrongly, C and C++ performance hot-rodders are wary of garbage collection and its perceived performance penalty.埃里克:不管正确与否,C和C + +性能热rodders是垃圾收集和警惕,认为它的性能损失。 What would you say to placate their fears?你会怎么说,以安抚他们的恐惧?

Andrei: First, allow me to clarify the purpose of garbage collection (GC).安德烈:首先,请允许我澄清的垃圾收集(GC)的目的。 GC is for writing safe programs with non-scoped allocation. GC是用于编写非安全范围分配方案。 If scoped allocation is all we need, we know how to typecheck programs for safety (Cyclone's regions and real-time Java are good examples); conversely, an unsafe program can perform unrestricted manual memory management.如果范围的分配是我们所需要的,我们知道如何安全typecheck方案(气旋的区域和实时Java是一个很好的例子),相反,一个不安全的程序可以不受限制地进行手动内存管理。 So again GC is for programs that a) need to be safe and b) use non-scoped allocation.因此,再次GC是为方案一)必须是安全和b)使用非范围的分配。

I'm rehashing this point because it's too often forgotten in arguments that frame GC as an indulgence, as the "easy way out" for languages and programmers alike.我再次提出这点,因为它往往被遗忘在争论该框架作为一个选区放纵,因为“容易的出路和编程语言”一样。 True, the infinite-memory model made practical by GC is easier to use, but the whole point of it all is memory safety.诚然,无限内存模型实际是由地方选区更容易使用,但它是整点的所有内存的安全。

Second, let's clarify that we're talking about a real cost, although the dimension of the cost isn't obvious.其次,让我们澄清,我们正在谈论一个真正的成本,虽然成本因素并不明显。 A 2005 study by Hertz and Berger, "Quantifying the performance of garbage collection vs. explicit memory management," has shown that real-world GC programs run about as fast as—and sometimes faster than—their deterministically deallocated exact equivalents, as long as they're allowed to occupy about 2–5 times more memory.按Hertz和伯杰2005年的研究,“量化的垃圾收集主场迎战明确内存管理性能,”表明,真实世界的气相色谱程序运行速度大约为,有时甚至高于-确定性释放他们的确切等值,只要他们获准占用更多的内存约2-5倍。 When a program runs low on memory, relies on data locality, or must compete with other processes for memory, the overhead of GC grows and could become catastrophic.当一个程序运行内存不足,依赖于数据局部性,或者必须竞争与其他进程的内存,地方选区的开销的增长,并可能成为灾难性的。 GC technology has improved since 2005, but with nothing earth-shattering, so I think that the above baseline holds.气相色谱技术自2005年以来有所改善,但没有什么惊天动地的,所以我认为上述的基准持有。

Third, I should point out that many programs don't really care about garbage collection.第三,我必须指出,许多方案并不真正关心垃圾收集服务。 RAM is plentiful, and few programs' core performance depends on data locality. RAM是丰富,数方案的核心性能数据局部性依赖。

Where does D stand?凡不Ð立场? D offers a garbage-collected heap used by default for class objects and built-in containers. D提供一个垃圾收集堆默认使用的类对象和内置的容器。 If you want to write a safe program, just use new and you're there.如果你想要写一个安全的方案,只要使用新的,你在那里。

But you're asking about hot-rodding.但你问热勒津。 If you want to fine-tune allocation, D's GC has a low-level interface that allows you to do unsafe things like freeing and resizing memory blocks.如果你想微调分配,D的选区有一个低级别的接口,允许你不喜欢和释放内存块大小不安全的事情。 Furthermore, you can use malloc() and free(), along with the rest of C's standard library, and even the nonstandard alloca(), without any overhead.此外,您可以使用malloc()和free(),随着C的标准库中休息,即使是非标准略卡(),没有任何开销。 Then, a D primitive function called emplace allows you to construct objects at specified memory locations (à la C++'s placement new operator).然后,一个D原始函数调用布设允许你指定的内存兴建地点(à拉的C + +的就业新经营者)的对象。

Most interestingly, D allows implementing memory-safe containers that internally use deterministic, unsafe allocation methods (for example, malloc() and free()), yet are encapsulated strongly enough to make any unsafe use impossible.最有趣的是,D允许实行内存安全容器内部使用确定性,不安全的分配方法(例如,的malloc()和free()),但都封装强烈足以让任何不安全的使用是不可能的。 I discuss that technique in depth in my InformIT article "Sealed Containers."我在我深入讨论Informit.com的一篇文章“密封式集装箱这种技术。”

D applications still link in the garbage collector, and operations such as using new or concatenating arrays will use it silently. D应用仍链接的垃圾收集,使用和操作,如新的或串联阵列将使用它静静地。 This is inconvenient for applications that need to make sure there is absolutely no use of garbage collection.这是需要的应用程序,以确保完全没有垃圾收集的使用不便。 Such applications can tweak settings to avoid linking in the garbage collector (which has a pluggable architecture).这种应用程序可以调整设置以避免在垃圾收集器连接(它有一个可插入的架构)。 All uses of GC operations would translate in link-time errors, which is okay but not ideal. GC的操作全部使用将翻译成链接时的错误,这是不错,但并不理想。

Walter Bright is considering adding a compile-time flag that would banish all constructs that make implicit use of the GC, in which case you'll know at compile time where the culprits are, and you can change your code accordingly.沃尔特光明正在考虑加入一个编译时标志,除去所有结构,使地方选区,隐含在这种情况下,使用您在编译时就知道那里的罪犯,你可以改变你的程式。 Specialized library support à la boost::shared_ptr would be necessary.专业图书馆支持拉刺激::shared_ptr的将是必要的。 All that work hasn't been done yet, but it's well-trodden ground, so I don't foresee any difficulties.所有这些工作尚未完成,但它的良好的践踏地面,所以我并不会有什么困难。

Eric: Every garbage-collected language must grapple with the thorny issue of resource reclamation: Some resources need to be released deterministically, and GC is inherently non-deterministic.埃里克:每个垃圾收集的语言必须努力克服的资源填海棘手的问题:有些资源需要被释放确定性,和GC本质上是不确定性。 How does D deal with this issue? Ð如何处理这个问题?

Andrei: If there's a magic bullet, we haven't found it.安德烈:如果有一个神奇的子弹,我们没有发现它。 Classes go on the garbage-collected heap; structs could go anywhere, but most often have a scoped lifetime.班去的垃圾收集堆;结构体可以去任何地方,但往往有一个范围的一生。 (As we just discussed, you could put anything anywhere with some effort; I'm talking about the path of least resistance). (正如我们刚才讨论的,你可以把任何文件都与一些努力,我对阻力最小的方向说话)。

The most difficult scenario here is a class that has a struct as a member.最困难的情况下在这里是一类具有结构为成员。 If the struct has a destructor, it will be run non-deterministically—or possibly not at all.如果结构有一个析构函数,这将是运行非确定性,甚至可能根本没有。 Currently the D garbage collector calls all class destructors; but, as we know from other languages, it's best not to count on that possibility.目前,垃圾收集器的D类析构函数调用所有,但是,当我们从其他语言的了解,最好不要指望这种可能性。 If you need timely resource release for such embedded structs, you'd best do it manually.如果您需要及时等嵌入式结构体资源释放,你最好做手工。

All that being said, D takes certain measures that aim at simplifying matters:所有这一切正说,d考虑简化问题的目的,在某些措施:

* The clear distinction between class and struct objects frames a design from day one, and it's a good statement of intent from the designer: "I define a class here, so I'm expecting an infinite lifetime model." *类和结构之间的明确区分对象框架从一开始设计,它是一个很好的设计师意图的声明:“我在这里定义一个类,所以我期待一个无限寿命模型。”
* D distinguishes between destruction and deallocation. *深区分破坏和释放。 C++ conflates the two notions, which confuses a lot of people in a lot of ways. C + +中的两个概念混为一谈,这在许多方面混淆了很多很多人。 You see, memory isn't about just any resource; it's a very special resource.你看,内存是不是只是任何资源,它是一个非常特殊的资源。 Unlike file handles, sockets, and mutexes, memory is the bedrock of the type system—everything that the language ever guarantees sits in memory.不同的文件句柄,插座,和互斥,内存的类型系统,一切的基石,该语言永远坐在保证在内存中。 Close a socket, and you'll have errors reading from it—but no real harm done.关闭一个套接字,你就会从它读有错误,但没有造成真正的伤害。 Use a dangling pointer, and anything could happen—the type system is unable to hold any guarantee.使用悬挂指针,什么事情都可能发生,类型系统是不能持有任何保证。

D defines for every object a primeval state in which it allocates no extra resources. D定义为每个对象的原始状态,其中没有任何额外的资源分配。 You can put any object into such a state by evaluating clear(obj), which is a sort of "operator delete without the dangers."你可以在这样一个国家通过评估任何对象明确(obj的),这是一个“经营者没有删除的危险排序。” The universal availability of such a primitive makes it easy for generic client code to deallocate resources safely.这种原始的普及,让普通客户端代码以释放资源安全。
* Finally, you don't need to use Java's awkward try/finally statements or the equally awkward C# using statement to clear resources in an orderly manner. *最后,你不必有秩序地使用Java的尴尬尝试/最后陈述或者同样尴尬的C#using语句,以明确的资源。 To be brutally honest, I believe that both constructs are missing the point by a mile; to be brutally narcissistic, I believe that D's scope statement is a game changer.要敢说真话,我相信这两个结构是由一英里缺少点;是残酷的自恋,我相信D的范围说明是一个游戏换。 If you want to execute code upon a scope's termination, all you need to do is this:如果你想要执行一个范围后的终止代码,你需要做的是这样的:

auto wbdc = new WhizBangDatabaseConnection("wbdb://meh");汽车wbdc =新WhizBangDatabaseConnection(“wbdb:/ /的MEH”);
scope(exit) clear(wbdc);范围(出口)清除(wbdc);

It's lightweight, it's safe, it's deterministic.它的重量轻,它的安全,它的确定性。 And it's a heck of a boon for reviewers, who won't need to follow complicated control flows.它是一个福音了评论,谁不会需要按照复杂的控制流啦!。 (You also get to execute code conditionally by replacing exit with success or failure.) I've been using this feature for years, and it scales phenomenally well. (您还可以通过执行替换成功或失败退出代码有条件地。)我已经使用了多年的这个功能,而且规模惊人好。

To summarize my answer: D doesn't have a foolproof integration of GC and deterministic resource reclamation.总结一下我的回答是:D不具有确定性的GC和资源回收万无一失的整合。 However, it does offer a coherent framework facilitating resource control, and a statement that makes manual reclamation robust and effective.但是,它提供一个一致的框架促进资源的控制,并声明,使人工填海强大和有效的。

Eric: I was surprised to hear that structs don't need inheritance—and from you, of all people, the standard-bearer for policy-based design!埃里克:我很惊讶地听到,结构体并不需要和您所有的人继承,标准,政策为基础的设计承载! In many of your C++ designs, you use parameterized inheritance to customize the behavior of value types.在你的C + +许多设计,使用参数化继承自定义的值类型的行为。 Why don't you need this feature in D?你为什么不这样需要在D功能?

Andrei: Inheritance has at least two important purposes:安德烈:继承,至少有两个重要目的:

1. 1。 The classic case is subtyping: "I want to inherit Button and tweak its behavior to allow an animated background."经典的例子是子类型:“我要继承巴顿和调整其行为,让一个动画背景。”
2. 2。 The other use is commonly called "inheritance of implementation": "I want to define Pool to offer what Factory offers, plus some other things."其他的使用通常称为“继承执行”:“我想定义池厂提供什么优惠,加上一些其他的事情。” But I'd call this "symbol table acquisition," because sometimes no implementation is involved—think std::binary_function.不过,我会称之为“符号表的收购,”因为有时没有参与实施,认为性病::binary_function。

In C++, you'd want to use inheritance in both cases, mostly for practical reasons—you want the benefit of the empty base optimization (EBO), and you wouldn't want to write a bunch of forwarding functions.在C + +,你要使用这两种情况下的继承主要是为现实的原因,你要的是空的基础优化(鄂博受益),而你不想写了一大堆转发功能。 In D, you'd use classes in the first case and structs in the second.在D,你在第一种情况下使用类和结构体中的第二个。

Getting the benefits of EBO in D is very simple because of the static if construct.在D获取利益的埃博很简单,因为如果静态构造。 You see, if scope(exit) is a game changer, static if is a game enabler.你看,如果范围(出口)是一个游戏换,如果是一个静态的游戏创造条件。 I was very bummed that C++0x, for all its size, doesn't include anything as mighty as that.我很郁闷的C + +0 X先生,感谢所有的大小,不包括这么强大的东西。 Here's how you avoid storing a useless member of type Factory inside an object of type Pool:这里是你如何避免内部的存储类型的对象池类型的工厂无用的成员:

struct Pool(Factory)结构中心(厂)
{ (
static if (Factory.tupleof.length == 0) {静如(Factory.tupleof.length == 0)(
// Factory has no per-instance state / /工厂没有每个实例的状态
alias Factory theFactory;别名厂theFactory;
} else {否则)(
Factory theFactory;厂theFactory;
} )
... ...
Object create() { return theFactory.create(); } }对象创建()(返回theFactory.create();))

tupleof yields the direct data members of a struct, so for an empty struct the corresponding tuple would have length zero. tupleof产生一个直接的数据成员的结构,一个空的结构相应的元组有这么长为零。 In that case, the code just creates a symbolic alias—theFactory is the same as Factory.在这种情况下,代码只是创建一个象征性的别名theFactory是一样的工厂一样。 Otherwise, Factory holds state, so you define an actual member.否则,工厂拥有国家,所以你定义一个实际的成员。 From here on, using theFactory.create() dispatches either to a static or a full-fledged member function.从现在开始,用theFactory.create()派遣或者到一个静态或正式成员函数。

If you want all symbols inside Factory to percolate through Pool's interface, you use a feature known as alias this:如果你想工厂内所有的符号,以通过渗透池的界面,您使用此已知别名的功能:

struct Pool(Factory)结构中心(厂)
{ (
... ... as above ...如上...
alias theFactory this;别名theFactory这一点;
} )

This feature works as you'd expect—if the compiler looks up a symbol inside Pool and doesn't find it, it continues down theFactory's symbol table.此功能为你期待,如果编译器里查找一池的象征,没有找到它,它继续向下theFactory的符号表。 (Notice how I combined static if and alias this for compounded effect!) This behavior is really what you want. (请注意我是如何结合静态和别名如果复合效应这个!)此行为是你真正想要的。

And then there's general static reflection, with which people have done crazy things—search online for whitehole d language, and you'll find a class WhiteHole that takes another class and implements all of its abstract member functions to throw.然后还有一般的静态反映,市民已为whitehole疯狂的事情,在网上搜寻D语言,你会发现一类WhiteHole这需要另一个类,并实现了它的抽象的所有成员函数抛出。 Great for mockup testing and partial implementations!伟大的实体模型试验和局部的实现!

Defining inheritance for structs (which is possible in a sound manner) might simplify certain scenarios, but it isn't an enabler.继承定义为结构体(这是可能的,在一个健全的方式)可能简化某些情况下,但它不是一个推动者。 I'm not sure whether such a feature would pull its own weight.我不知道这种功能将撤出其自身的重量。

Eric and Andrei wrap up their discussion of D in "Interview with Andrei Alexandrescu (Part 3 of 3)."埃里克和安德烈总结了他们在“面试的D讨论与安德烈Alexandrescu(3 3部分)。”



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics