Why can't the meaning of a base class specification recursively depend on itself in C#?

前端 未结 1 405
清歌不尽
清歌不尽 2021-01-31 20:32

The following piece of C# code does not compile:

public class A
{
    public interface B { }
}              
public class C
    : A,
      C.B // Error given her         


        
1条回答
  •  生来不讨喜
    2021-01-31 20:50

    I have struggled with the issues you bring up for countless hours over the last few years. A detailed discussion of all the issues you raise would take me several hours to type up, so I'll just summarrize:

    First, it turns out that even with that "temporarily assumed to be object" clause that Mads and I added to try and tighten up that section of the spec, this section of the spec is still not well-founded. The "how to bind a name to a type" bit of the specification assumes that all nesting and inheritance relationships are known and consistent at the point at which the lookup happens, but of course obviously that cannot be the case since the whole reason we are doing a name lookup in the first place is to determine a base type. If I had my notes with me I could give you a number of examples of crazy type hierarchies where combinations of generics, nestings, interfaces and base classes put the compiler into situations where how you determine what a given name means depends on the order in which you are figuring out the base classes.

    Obviously that is not a good place to be. We do not want the meaning of a C# program to differ when you re-order the classes in a file!

    Second, we are constrained by what can be represented in metadata.

    Third, historically we have been constrained by what can be efficiently emitted into metadata. Previous versions of the metadata emitters had performance or correctness issues if you tried to emit derived types before base types or inner types before outer types. (I attempted in C# 4 to address this by writing a topological sorter that would find an efficient ordering if any existed, but the change proved to be sufficiently complicated and dangerous that we decided to not take the change until Roslyn. In Roslyn we are using a completely different emitter.)

    Fourth, it is rare that these sorts of topologies turn up in real production code; you are apparently an exception to that rule.

    Fifth, one of our major goals for the language is to make it a "pit of quality" language, where the features of the language lead one to write programs that are both correct and comprehensible. Allowing the sorts of crazy "curiously recurring" patterns that you see in C++ templates is explicitly not a goal of the C# language team. We're not interested in providing a theoretically complete type system; we're interested in making it easy to represent that an Employee is a kind of Person.

    All of these factors are working against making circularities in base class and nested class relationships more legal. As much as I personally would enjoy the challenge of coming up with a well-founded system for resolving circularities in base types in a manner that does not break any existing code, it is not a high enough priority; we have a long list of stuff we want to improve for Roslyn, and the base class resolution algorithm is far from the top of that list.

    0 讨论(0)
提交回复
热议问题