`
RednaxelaFX
  • 浏览: 3047758 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

Scott Peterson: Variance, Thy Name is Ambiguity

    博客分类:
  • C#
阅读更多
原文作者:Scott Peterson
原文地址:http://themonkeysgrinder.blogspot.com/2009/06/variance-thy-name-is-ambiguity.html


Scott同学关于co-/contravariance的几个帖子都值得一读。这篇算是比较总结性的。另外几篇的链接就在文中开头几句。
若某个类实现了同一个co-/contravariance接口的不同泛型类型,然而这几个泛型类型参数是有继承关系的,那么调用某个接口方法的时候,应该选用什么版本的问题上会有歧义。Scott同学认为应该在规范中写明一个确定的解决歧义的方法。
Scott Peterson 写道
Previously
On This Blog...


"I love you, Generic Variance, and I want your babies RIGHT NOW!"

"I think there's something you should know about Generic Variance..."

"I can change him!"

And now, the thrilling continuation...


I've just sent my recommendation to the ECMA 335 committee regarding the generic variance problem. I present it here for your reading pleasure:


Quick Recap

The following is an example of an ambiguous circumstance involving generic variance, the very sort over which we have all lost so much sleep:

.class interface abstract I<+T> {
    .method public abstract virtual instance !T Foo ()
}

.class A {}
.class B extends A {}
.class C extends A {}

.class X implements I<class B>, I<class C> {
    .method virtual instance class B I[B].Foo () { .override I<class B>::Foo }
    .method virtual instance class C I[C].Foo () { .override I<class C>::Foo }
}

// Meanwhile, in some unsuspecting method...
I<A> i = new X ();
A a = i.Foo (); // AMBIGUITY!


Give a Runtime A Bone

To disambiguate such situations, we introduce a new custom attribute in the BCL. For the sake of example, let's call it System.PreferredImplementationAttribute. The PreferredImplementationAttribute is applied to a type and indicates which implementation should be selected by the runtime to resolve variance ambiguities. Our above definition of the type X would now look like this:

.class X implements I<class B>, I<class C> {
    .custom instance void System.PreferredImplementationAttribute::.ctor (class System.Type) = { type(I<class C>) }
    .method virtual instance class B I[B].Foo () { .override I<class B>::Foo }
    .method virtual instance class C I[C].Foo () { .override I<class C>::Foo }
}


New Rules

With the addition of this attribute, the runtime requires that any type defined in an assembly targeting the 335 5th edition runtime which implements multiple interfaces that are variants of a common generic interface MUST specify ONE AND ONLY ONE PerferredImplementationAttribute for EACH of the potentially ambiguous common interfaces, and that each such specification of a PerferredImplementationAttribute must reference an interface implemented by the type that is a legal variant of the ambiguous common interface. In other words, all possible ambiguities MUST be disambiguated by the use of PreferredImplementationAttribute custom attributes. If a type does not satisfy these rules, the runtime MUST throw a System.TypeLoadException.

As this rule only applies to assemblies targeting the new version of the runtime, old images will continue to execute without issue. If the committee prefers, the resolution of ambiguities in old types may remain unspecified, or alphabetical priority could be codified in the spec to standardize such behavior. I would be fine leaving it unspecified.

Custom Attributes vs. Metadata

Ideally, I feel disambiguation information belongs in the type metadata structure rather than a custom attribute. If the committee feels that amending the metadata specification is tenable, I would recommend doing so (though I don't have any thoughts at this time on the exact logical or physical nature of such an amendment). If, on the other hand, changing the metadata spec at this point in the game is not feasible, then a custom attribute will just have to do. I see the addition of one custom attribute type to the Base Class Library as entirely justified.

An Aside to Our Friends on the 334 Committee

As a note to language designers targeting the runtime, I personally would consider it obnoxious if developers where burdened with the manual application of such a custom attribute. C# and other languages would do well to prohibit the direct use of the custom attribute, favoring instead a special syntax to denote the preferred implementation (the "default" keyword comes to mind in the case of C#). If this committee changes the type metadata spec to include preferred implementation information (and does not introduce a custom attribute type for that purpose), then special language syntaxes will be necessary.

An Alternative

In the interest of completeness, I will describe an alternate (if similar) approach to the ambiguity resolution problem. Rather than annotate types to indicate which of their interface implementations will satisfy ambiguous calls, the preferred implementation could be denoted on a per-member basis. Referring again to our original type X, this solution would modify that type thusly:

.class X implements I<class B>, I<class C> {
    .method virtual instance class B I[B].Foo () { .override I<class B>::Foo }
    .method virtual instance class C I[C].Foo () {
        .override I<class C>::Foo
        .custom instance void System.PreferredImplementationAttribute::.ctor ()
    }
}


The member I[C].Foo is annotated with the System.PreferredImplementationAttribute, indicating that it will be selected by the runtime to fulfill otherwise ambiguous calls to I<T>.Foo. Note that in this solution the constructor to the PerferredImplementationAttribute type is parameterless. The runtime ensures that for EACH of the members of an interface which is the common variant of two or more of the interfaces implemented by a type, ONE AND ONLY ONE of the implementations for that member is flagged as "preferred."

Per-member preference definition affords developers more control but costs runtime implementers time, effort, and simplicity. I also don't envision many scenarios when developers would desire per-member control over implementation preference. I personally find this approach less tasteful than the per-interface solution but I mention it here, as I said, for completeness.

One More Thing...

There remains a situation on which there are varied opinions:
.class interface abstract I<+T> {
    .method public abstract virtual instance !T Foo ()
}

.class A {}
.class B extends A {}

.class X implements I<class A> {
    .method virtual instance class A I[A].Foo () { .override I<class A>::Foo }
}

.class Y extends X implements I<class B> {
    .method virtual instance class B I[B].Foo () { .override I<class B>::Foo }
}

// Meanwhile, in some unsuspecting method...
I<A> i = new Y ();
A a = i.Foo ();


In this situation I<A>::Foo is called on an object of type Y. There is an implementation of I<A>::Foo in Y's type hierarchy (X::I[A].Foo), but there is also an available implementation which is a legal variant of I<A> in Y itself (Y:I[B].Foo). Does the runtime favor the exact implementation, or the more derived variant implementation? I don't have strong feelings on the matter, but my slight preference is for favoring the exact implementation.

The runtime is deciding on behalf of the developer which implementation is most appropriate. It could be argued that an exact implementation, wherever it is to be found the type hierarchy, is more appropriate than a variant implementation.

Also - and this is an implementation detail which should not outweigh other considerations but may be useful to keep in mind if all other things are equal - Mono stores a type's implemented interfaces in a binary tree, meaning that finding an exact implementation is an O(log n) worst-case operation, whereas finding a legal variant interface among a type's implemented interfaces is an O(n) worst-case operation (all interfaces must be examined to see if a legal variant exists among them). I haven't heard of any way to do O(log n) (or better) lookup of variants. With such popular types as IEnumerable`1 becoming variant, the superior time complexity could make a difference.
分享到:
评论
1 楼 RednaxelaFX 2009-09-07  
诶,可惜这个问题看来是不会有什么好的解决办法。Eric Lippert说他们动用的MSR的强人搞了半天还是没搞出特别好的解决方案,干脆就不管泛型协变的歧义了。等VS2010 Beta 2出来看看有没有什么变化……

相关推荐

    Dekker算法Peterson算法

    ### Dekker算法与Peterson算法详解 #### 一、Dekker算法 ##### 1.1 初步设想 在初步设计中,Dekker算法通过一个全局变量`turn`来控制两个进程P0和P1对临界区(Critical Section, CS)的访问。这个变量的值为0或1,...

    t=3 BCH码peterson解码算法(verilog)

    Peterson解码算法是BCH码的一种实用解码方法,由G. R. Peterson在1960年提出。这个算法利用了伽罗华域(GF)上的多项式运算,特别是乘法和除法,来找出可能的错误位置。在Verilog中实现Peterson解码器,意味着将这个...

    线程同步机制代码,用c++写的,:使用Windows互斥信号量操作函数和同步机制的Peterson,实现进程互斥和同步

    小实验三:根据同步机制的Peterson软件解决方案尝试自己编程实现线程同步机制和用于上述线程并发问题的解决,并基于程序运行时间长短将其与基于Windows互斥信号量的线程同步机制的效率展开比较。 实验要求:线程主体...

    线程同步-mutex方案-Peterson方案

    本文将详细探讨线程同步中的两种经典解决方案:mutex方案和Peterson方案,以及它们在Java环境中的实现。 首先,我们来了解mutex(互斥锁)方案。Mutex是一种基本的同步原语,它的主要目标是防止多个线程同时进入...

    Peterson_producer_consumer.zip_c语言Peterson

    标题中的“Peterson_producer_consumer.zip_c语言Peterson”指的是一个使用C语言实现的基于Peterson算法的生产者-消费者问题实例。生产者-消费者问题是多线程编程中常见的同步问题,而Peterson算法是解决两个进程...

    peterson_peterson_

    标题 "peterson_peterson_" 和描述 ";lkg" 提供的信息有限,但根据标签 "peterson",我们可以推测这里可能是指 Peterson 同步算法。Peterson 算法是一种经典的解决两个进程互斥访问共享资源的算法,由 Gary L. ...

    Computer Networks A Systems Approach(5th) Larry L. Peterson

    Larry L. Peterson, Bruce S. Davie, Computer Networks: A Systems Approach

    course_description.pdf

    《算法在科学应用II》(Algorithms for Science Applications II) 是一门由Janet Peterson教授和John Burkardt博士共同授课的课程,旨在为学生提供解决离散问题的算法基础,如排序、搜索数组、调度、最优化路径(如...

    Introduction to spread spectrum communications_Roger L. Peterson1995

    Peterson)在1995年所著的《扩频通信导论》的知识点总结。 首先,《扩频通信导论》是关于扩频技术的权威性入门书籍,该技术是现代无线通信中的一种重要传输方法。作者罗杰·L·彼得森,与合著者戴维·E·博斯...

    Petri网理论和系统模拟(JAMES L.PETERSON著 吴哲辉译1989)

    Peterson)的经典著作,由吴哲辉翻译成中文,出版于1989年。这本书深入探讨了Petri网作为一种强大的数学工具在系统建模和分析中的应用。Petri网是一种图形化模型,用于描述和理解复杂系统的并发行为,特别适用于...

    peterson jb

    Peterson在其著作中探讨了意义的三种形式和管理复杂性的方法。首先,Peterson指出许多心理学模型,即使是像Gray(1982)那样复杂的模型,也是基于世界由独立存在的物体或刺激构成的假设。然而,这一假设是错误的,...

    进程同步之临界区域问题及Peterson算法1

    临界区域问题和Peterson算法就是解决这一问题的关键技术。 1. **临界区域问题**: 临界区域是指进程中用于访问共享资源的一段代码,每次只有一个进程能够执行这段代码。临界区域问题的出现是因为并发执行的进程...

    Peterson Newman访谈数据集.zip

    《Peterson Newman访谈数据集:探索自然语言处理的深度与广度》 在现代信息技术的浪潮中,自然语言处理(Natural Language Processing, NLP)作为人工智能领域的重要分支,正在逐步改变我们与计算机交互的方式。而...

    BCH码verilog源码(peterson算法)

    Peterson算法是实现BCH码的一种常见方法,它主要用于生成和解码BCH码。Peterson算法主要由两个关键部分组成:生成多项式的选择和Galois域GF(p^n)上的乘法运算。这里的p通常为2,n是码字长度的一个参数。生成多项式是...

    算法与数据结构 分布式算法课程 第12章 ASM - Peterson’s算法 共43页.pdf

    Peterson算法的特点在于它提供了一种简单而有效的方法来实现进程间的互斥访问,同时保证了锁出自由性(Lockout-Freedom)——即使在存在公平性的低级执行过程中,只要所有用户最终都释放了资源,则任何进入尝试状态...

    Error-Correcting Codes - Revised, 2nd Edition.djvu

    Error-Correcting Codes, by Professor Peterson, was originally published in 1961. Now, with E. J. Weldon, Jr., as his coauthor, Professor Peterson has extensively rewritten his material. The book ...

    Jordan-Peterson-Tribute-Page:这是Jordan B. Peterson博士的致敬页面

    【标题】"Jordan-Peterson-Tribute-Page"是一个以知名心理学家和作家Jordan B. Peterson博士为主题的致敬页面。这个项目旨在通过网页的形式向Peterson博士表达敬意,可能是为了展示他的生平、思想、著作或者对他的...

    计算机网络第六版答案

    21. The maximum emission rate is 500 packets/sec and the maximum transmission rate is 350 packets/sec. The corresponding traffic intensity is 500/350 =1.43 &gt; 1. Loss will eventually occur for each ...

Global site tag (gtag.js) - Google Analytics