dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.06k stars 4.04k forks source link

Language Feature: Extension Everything #11159

Closed gafter closed 7 years ago

gafter commented 8 years ago

There are existing proposals/requests #3357, #4945, #5165, #5624, #6136, but this is a slightly different take. One difference is that qualification with this would be required inside, at least for access to extension members.

Extension Everything for C

This proposal gives a way to define new kinds of extension members. Today it is possible to define methods that act as if they are instance methods of the extended type. This proposal expands that capability, supporting both static and instance members, and supporting (or at least discussing) all of the kinds of members you might want to declare.

Here is an example that summarizes the new proposed syntax forms:

// "extension" is a new (contextual keyword) modifier, permitted before the keyword "class".
// It can be combined with "partial". It produces a static class that one would not normally use
// directly, however there will be syntax forms for directly using all of the named members
// (but not the operators) as members of this class.
public extension class ListListExtensions<T>
  : List<List<T>> // the "extends" clause names the extended type. May be an interface
  // , Interface  // we do not permit adding interfaces in the base clause
{
   // static variables are no problem, and hosted in the container ListListExtensions<T>
   private static int _flattenCount = 0;

   // static methods are simply hosted in the container, ListListExtensions<T> in this case
   public static int GetFlattenCount()
   {
     return _flattenCount;
   }

   // static properties are similarly hosted in the container.
   // They translate into a static "indexed" property, indexed with a "this" (extension) parameter.
   public static int FlattenCount
   {
       get
       {
         return _flattenCount; // extension static variable access
       }
   }

   // instance methods are compiled using the same pattern as existing instance extensions.
   // The additional hidden parameter is named @this from the SemanticModel's point of view.
   public List<T> Flatten()
   {
     // Within instance members, "this" is of type List<List<T>>
     _flattenCount++;
     ...
   }

   // Extension indexers permitted, both static and instance.
   public List<List<T>> this[int[] indices] => ...;

   // We do not support instance extension fields, but we could support them in the future
   // if the type being extended is a reference type, using ConditionalWeakTable.
   // public int InstanceMember;

   // We do not support constructors, but we could support them in the future
   // by creating an ordinary method with a special name. Some design work would
   // be required to ensure the following syntax is possible, or to design an alternative.
   // public List<List<T>>(int defaultSize) : this(...) { ... }

   // Operators are permitted. Operators are required to have a parameter (or return type,
   // for implicit conversions) of the extended type.
   // All of the lookup rules for operators will need to be amended to look in extension types
   // that are in scope.
   public static implicit operator List<T>(List<List<T>> self)
   {
     return self.Flatten();
   }

   public static implicit List<List<T>> operator +(List<List<T>> left, List<List<T>> right) => left.Concat(right);
}

Limitations:

Substantial LDM design work will be required

alrz commented 8 years ago

Why we still require to name the extension class while it can be self explanatory like:

public extension int { }
// instead of
public extension class IntegerExtensions : int { } 

Using class-base to specify the target type can get weird in case of generic, static or array types:

public extension class IntegerArrayExtensions : int[] { }
// for defining static extension methods ..
public extension class ConsoleExtensions : Console { } 
// would this be allowed?
public extension class GenericExtensions<T> : T /* where T : ... */ { }

Alternatively,

public extension int[] { }
public extension Console { }
public extension<T> T /* where T : ... */  { }
public extension<T> List<List<T>> { }

This would reserve class-base for when we have virtual extension methods (#258) to add interface implementations to existing types (#8127).

svick commented 8 years ago

I apologize if I misunderstood the proposal, but I don't think the way it treats this makes much sense.


return this._flattenCount;

So, static extension members are accessed from static extension members using this., which looks like instance member access? I think that's very confusing.


The additional hidden parameter is named @this from the SemanticModel's point of view.

So, to keep a static cache of the last instance some member was called on, I would have to write the following?

this._cache = @this;

Again, quite confusing.

svick commented 8 years ago

@alrz I think the name can be useful. You can use it to explicitly call the extension method as a normal method (e.g. Enumerable.ToList(query)). And it also allows you to select only some extension types from a namespace (e.g. using static System.Linq.Enumerable;).

gafter commented 8 years ago

@svick

I apologize if I misunderstood the proposal, but I don't think the way it treats this makes much sense.

It was messed up. Static members are accessed by qualifying with the extended type. I've fixed up the OP.

So, to keep a static cache of the last instance some member was called on, I would have to write the following?

this._cache = @this;

Again, quite confusing.

The @ is to show that it is an ordinary identifier when viewed through the symbol table (compiler API), and that you can access it that way if you want. You can still refer to it using the this keyword.

svick commented 8 years ago

@gafter Ok, now it looks good to me.

alrz commented 8 years ago

@svick Currently you can not use using static for extension methods. Also they can't be defined in generic classes. As you can see in the original post ListListExtensions<T> is a generic class (I'm not saying that this can't be done in the new syntax, though).

You can use it to explicitly call the extension method as a normal method

If that's your concern you'd better use the existing extension syntax (that'd be the benefit for the old syntax to be not totally deprecated). But I don't expect to be able to use extension methods as if they are static methods when I explicitly defined them in an extension declaration as non-static members!

And it also allows you to select only some extension types from a namespace

I didn't suggest that they be in the scope out of nowhere, just like what we have with extension methods, the containing namespace must be imported using using.

I think naming classes like extension class WhateverExtensions : Whatever is just too repetitive.

svick commented 8 years ago

@alrz

Currently you can not use using static for extension methods.

This compiles fine for me:

using static System.Linq.Enumerable;

class Program
{
    static void Main()
    {
        new int[0].ToList();
    }
}
alrz commented 8 years ago

@svick Oh right. But this doesn't ToList(new int[0]); assuming using static System.Linq.Enumerable;.

quinisext commented 8 years ago

While I do agree that naming an extension class is useful, I think that (formally) deriving this class from the extended class makes little sense overall.

public class ClassToExtend
{
    public ClassToExtend (int arg) { ... }
}

public extension class ExtensionClass : ClassToExtend
{
    // For when constructors are supported.
    public ExtensionClass (int arg1, int arg2) { ... }
}

...

// Unlikely the desired syntax, but should make sense if
// ExtensionClass is a descendant of ClassToExtend.
ClassToExtend a = new ExtensionClass(1, 2);

// Likely the desired syntax.
ClassToExtend b = new ClassToExtend(1, 2);

// Totally not what we need.
ExtensionClass c = ...

In short, extension class is not a descendant of the extended class, so it shouldn't look like one. The syntax could rather go like this:

public extension class ExtensionClass<T> for ClassToExtend<T> { ... }
alrz commented 8 years ago

@quinisext

I do agree that naming an extension class is useful,

Can you give some examples, how is that useful? I also note that if your extension class is generic, which it very may well be, you can't use using static as @svick mentioned. This is not a problem right now because extension methods are generic, not the enclosing class, so using static is fine. Even if you could "use extension methods as if they are static methods even though you explicitly defined them as non-static members" which makes little sense, type inference won't help you and you will need to explicitly specify type arguments. So for complete compatibility with existing extension classes, generated class must not have a type parameter list and perhaps with an optional name, because it's not always useful.

quinisext commented 8 years ago

@alrz Even if the name is optional, I believe the class keyword should be obligatory.

public extension class<T> for T[] { ... }

(I'm not insisting on for, of course, just not :). It makes the code clearer to read (especially when extension is not highlighted by the editor) and more uniform, and most probably easier to parse. Without it, the extension would probably need to be promoted to a full-fledged keyword status. Naming makes the code more uniform too, though. Actually i'd rather have as little new syntax/keywords as possible:

// Only a for-part is something new; and no new keywords, contextual or not.
public class ArrayExtension<T> for T[] { ... }

// Easier to get as a special case of the previous. Still no good looking.
public class for ExtendedClass { ... }
public class<T> for T[] { ... }

Names would allow to using static an extension type without using the rest of its namespace. Names are useful to me personally, due to the way I use reflection (which I do extensively) (can be achieved through attributes though). Names would allow to create two distinct extension classes in one namespace, which can be using static separately. They're also future-proof, in case some day language gets parametrized usings.

using static SomeNamespace.ExtensionClass<System.String>;

Admittedly these all are pretty esoteric.

Still the syntax you proposed does seem appealing to me, I'm just afraid it would complicate parsing, and the word "extension" is too good a word to make it a keyword. Maybe something like

public extending<T> T[] { ... }
omariom commented 8 years ago

Interesting :+1:

Which existing types in CoreFx or third parties could benefit from the feature?

MgSam commented 8 years ago
paulomorgado commented 8 years ago

@MgSam;

  • Spec seems interesting and reminiscent of some previous community suggestions, however, I personally think you don't get much value-add over existing extension methods unless you add the ability to have data associated with an instance (extension instance properties).

Isn't this supposed to be static extensions? Why is "add the ability to have data associated with an instance (extension instance properties)" important?

  • Agree with previous comments that re-using the extends operator, : , is a bad idea. It already has too many meanings, don't add another one.

That's when Java and Visual Basic start to look good for having extends and implements keywords. But for C#, I think it's too late to go that way. Another punctuation?

MgSam commented 8 years ago

@paulomorgado My point was this seems like a lot of design work for very little benefit over current state if adding state to the instance is not on the table. Having extension methods on static classes are the only truly new use cases in this spec, but even that is less useful than it once was with C# 6.0's using static feature. (You can just dump all the static classes you want into scope in your file)

Agree the ship has sailed long ago on extends and implements, but that doesn't mean we should perpetuate the mistake by reusing : yet again. Make it an English-language keyword word rather than punctuation.

quinisext commented 8 years ago

@MgSam I use extension methods extensively (sorry), so I miss such feature for quite some time (it is in Delphi/Free Pascal for a long time now). It allows adding properties using standard syntax, and that is enough benefit for me on its own.

MgSam commented 8 years ago

@quinisext I use extension methods extensively too. The only difference this proposal makes for properties is that instead of having extension methods SetFoo and GetFoo, you now can make those a property. But they still can only address static data. That doesn't seem like it's worth the design cost to me.

On the other hand, if there is a realistic way to associate instance data, then it becomes a big win. WPF has the whole concept of "attached properties", which are absolutely nasty to declare, yet this proposal still doesn't fill the huge niche that those attempted to address. The C# design team tried to tackle extension everything once before and rejected it because the design was incompatible with this use case.

gafter commented 8 years ago

I consider "extension static members" including "extension operators" the most important benefits of this.

quinisext commented 8 years ago

@MgSam I'm actually more interested in readonly properties. But having properties you can always implement your own mechanism of attaching them:

public class ExtensionClass for System.Windows.Controls.Button  // Whatever would be the syntax.
{

    // You would still need to deal with abandoned values, but there is probably no good way
    // to solve this problem in general case.
    private static Dictionary<MyClass, int> values;

    public MyIntProperty 
    {
        get { return value[this]; }
        set
        {
            values[this] = value;
        }
    }

    // Some neat tricks.
    public double CanvasLeft
    {
        get { return Canvas.GetLeft(this); }
        set { Canvas.SetLeft(this, value); }
    }

    public RoutedEventHandler ClickHandler
    {
        get { return Click;   }
        set { Click += value; }
    }

    // Extension constructor.
    public ExtensionClass (out Button variable)
    {
        var result = new Button();
        variable = result;
        return result;
    }
}

// Now also this coud work.
var button = (Button)null;
var Panel = new System.Windows.Controls.Canvas
{
    Children =
    {
        new Button (ref button)
        {
            CanvasLeft    = 20,
            MyIntProperty = 42,
            ClickHandler  = (s, e) => { DoSomething(); }
        }
    }
};
button.Click += MyOtherHandler;

You can't do these things with Set/GetSomething().

Extension constructors may work well with immutable data. And extension operators would allow you to connect mathematical types that was initially unaware of each other.

HaloFour commented 8 years ago

If the concept of "extended" state is to be on the table I would like to see something come out of the CLR that would enable such functionality without incurring the penalties associated with ConditionalWeakTable. Otherwise my opinion is that C# shouldn't encourage such use and that if people want the "extended" state then they can simply follow those patterns manually.

Beyond that, extension static methods, properties and operators do seem like they'd be worth it. Extension constructors are weird but I can see their value. Maybe that could lead to asynchronous constructors #6788.

jveselka commented 8 years ago

@quinisext That's a memory leak. Correct implementation would need something like WeakReference Dictionary. I'd rather see language support for extension fields than implementing this (I would probably get it wrong). EDIT: I have just found out that there is something like WeakReference Dictionary in .NET already - System.Runtime.CompilerServices.ConditionalWeakTable class. It's only downside is restricting values to reference types.

quinisext commented 8 years ago

@zippec

That's a memory leak.

That's exactly what I meant by

You would still need to deal with abandoned values.

As I said, I don't see a good general solution, that can be used as an implementation for extension fields/auto-properties. But that was not the point of the example. The point was to show that extension classes are worth implementing even without that particular feature. As to the feature, it would be nice to have it somehow, but is there a really good way to make it? If you do it manually, you at least see what's going on and understand the costs and limitations.

VSadov commented 8 years ago

Another idea for the syntax - just use the type that we are extending, possibly with additional constraints.

public extension class List<T> {..}
public extension class List<T> where T: List<int> {..}
public extension class List<T> where T: class {..}
public extension class List<T> where T: int {..}
HaloFour commented 8 years ago

@VSadov

What would the name be for the generated static class if the developer doesn't explicitly provide one? Whatever it is would have to be predictable in order for a recompilation to not break existing consumers, and it would have to be resilient to collisions in case you want to extend two different classes named List, or with a different arity of generic parameter types.

quinisext commented 8 years ago

@VSadov Would it scale well?

public extension class int[] { ... } // Formally works but unnatural for c#.

Also, as HaloFour said, what is the "predictable" name for int[] extension class? It is just unobvious in general case.

VSadov commented 8 years ago

The challenge here is to have a syntax very similar to a class definition, but yet we want to sneak in a type reference to a potentially more constrained instantiation of a type - like List< int >.

My suggestion may not even be better than what @gafter proposed. Just another idea how we can abuse preexisting syntax.

Having no name is ok. Not everything in the source ends up with formal names. As implementation, compiler can generate something unspeakable and specify applicability of the extension container via attributes.

HaloFour commented 8 years ago

@VSadov

Unspeakable would be perfectly fine as long as the name is determinstic based on the extended type.

:spaghetti:

Extended Generated Name *
int[] 'System.Int32[]<>Extensions'
List<T> 'System.Collections.Generic.List1<>Extensions'` **
List<int> 'System.Collections.Generic.List1Extensions'`

* Note that the namespace is embedded in the class name. ** Would the static type itself be generic, or would only the static extension methods be generic?

svick commented 8 years ago

@HaloFour What if you extend the same type twice in the same namespace (most likely from different files)? E.g.:

public extension class List<T>
{
    public void ExtensionMethod1() {}
}

public extension class List<T>
{
    public void ExtensionMethod2() {}
}

The only solution I can think of would be to combine both extensions into the same class.

nguerrera commented 8 years ago

@gafter Yes, yes, yes! I love this proposal. It would go a long way to allow layered designs without sacrificing on discoverability. :) We struggled with it consistently in the evolution of .NET Core and this would let us restore source compatibility to some of the harder decisions that were made. For example, Delegate.CreateDelegate and Char.GetUnicodeCategory could be made to work again.

// We do not support instance extension fields, but we could support them in the future // if the type being extended is a value type, using ConditionalWeakTable.

Should this read "... if the type being extended is not a value type, ..."?

nguerrera commented 8 years ago

@VSadov @HaloFour Maybe I'm missing something, but if the container is unspeakable than there will be no syntax for forcing a call to an extension over a first-class member defined on the target, or to disambiguate between competing extensions. It would also seem to leave any .NET language that has not caught up to the metadata conventions backing this with no way to invoke these members.

HaloFour commented 8 years ago

@nguerrera That's a good argument for requiring the developer to explicitly name the extension class.

alrz commented 8 years ago

@VSadov

The challenge here is to have a syntax very similar to a class definition

I think it doesn't make sense to do that because extension is essentially a different kind rather than just a modifier. For example, take Module in VB, it turns everything to a Shared member (and Shared itself is not permitted), it's not a modified Class it's a different kind. In contrast, we require to use static on members in a static class, so there is nothing magical about static modifier. On the other hand, extension does permit static modifier on members, it's a separate kind in any way.

Note that with your suggestion it's not possible to declare an extension class for a generic T.

Another thing about existing extension classes is that they are always non-generic classes so I'm thinking for maximum compatibility e.g. rewriting existing extension classes as extension declarations, it should generate a non-generic class, regardless of the extension itself being generic.

omariom commented 8 years ago

Would be nice if extension members took structs by ref, not by copy.

HaloFour commented 8 years ago

@omariom

165 seeks to allow that for C# extension methods in general. As mentioned there this is already a supported feature in VB.NET.

Question here would be if #165 is adopted then would extension classes always expose the this argument as ref if the extended type is a value type?

VSadov commented 8 years ago

Re: unspeakable name. Yes. After thinking about it, it seems that sooner or later there will be a need to invoke an extension directly. That would require the container be referable by name, so my suggestion would not work.
I am convinced.

gulshan commented 8 years ago

Rust's attaching methods to the data is kind of similar.

Thaina commented 8 years ago

@HaloFour I think it should. And while this is new feature anyway we could have it better than we already have

And I could say that we most likely to use extension method on struct. Because normal class could be extended as a derived class but struct cannot. But to have extension method only pass by value stop it. And it is design flawed all along that it can't fix because backward compatible

So now we can fix it with new syntax then it is a must

Thaina commented 8 years ago

Still I'm not agree with operator. Because we can't find reference of duplicate operator like we can find member

masaeedu commented 8 years ago

@gafter Would it not be possible to support getter-setter properties without supporting fields? There is still some debate about the impact of ConditionalWeakTable, but supporting getters/setters:

  1. Allows users to add convenience properties to classes they can't/won't extend
  2. Allows users who accept the costs of ConditionalWeakTable to explicitly implement "fields" using static members for bookkeeping and properties for access
gafter commented 8 years ago

@masaeedu If you can't have a field, where would you store the ConditionalWeakTable?

masaeedu commented 8 years ago

@gafter Static field, and I'd do the bookkeeping for associating instances with their data explicitly.

gafter commented 8 years ago

@masaeedu Yes, if we support static fields then you can use ConditionalWeakTable to simulate instance fields for reference types.

VSadov commented 8 years ago

You would need to box simulated fields to maintain right semantincs. Fields are variables - can be passed byref and so on.

So it would actually need to be something like ConditionalWeakTable<TContainer, StrongBox<TField>>

It would not be very efficient, but yes, extension fields are possible in theory.

Thaina commented 8 years ago

I think we should not making extension field automatically like that. We may want to implement it with our own

jnm2 commented 8 years ago

@gafter Why would you not support static fields? If you don't, the workaround would be to create a new static class to hold the fields which is a bit ugly. Especially for encapsulation.

iam3yal commented 8 years ago

@gafter Will this "we do not permit adding interfaces in the base clause" be allowed at some point? I assume it wouldn't, I know that it requires CLR support but besides this is there any reason not to allow it?

alrz commented 8 years ago

@eyalsk It can get out of hand,

// lib 1
interface A {}
interface B {}
// lib 2, references: lib 1
class C : A {}
// lib 3, references: lib 1 and 2
void F(A a) {}
void F(B a) {}
F(new C()); 

The last line compiles but if you reference another library which happen to have an extension for C that implements B, it suddenly breaks. In Rust, however, either the target type or the trait must be declared in the same crate. I suppose this can be enforced in C# as well. See #8127.

iam3yal commented 8 years ago

@alrz Thank you. :)

andrew-skybound commented 8 years ago

I apologize if this syntax has been suggested before and I somehow missed it. This suggestion requires no changes to the C# grammar, and works for pretty much any kind of member you want to add. In fact, this example below is valid C# 3.5.

I like the fact that this syntax is explicit, that these declarations look exactly like what they are: static methods of a static class to which the compiler is redirecting.

I'm not a big fan of unnamed "extension classes" in C#. This may work well for other languages but I don't think it's appropriate for a CLR language designed to interoperate with other languages. The first problem is how these extension classes will appear when consumed outside of C# or by previous versions of the language. Next, there is ambiguity between what is a member of the extension class, and what is a member of the class being extended. And finally, there are many features of ordinary classes that need to be restricted in an "extension class" context: protection levels, finalizers, virtual/override/new, fields, interface implementations, and probably more. The cognitive load here is quite high--it's another whole kind of type to learn.

So, there is no magic happening in this syntax; no automatic weak-reference dictionary for properties or events. You're free to do that on your own, or perhaps the framework could provide something a little more friendly than ConditionalWeakTable. I think this is the best way to handle the situation because many types expose their own property/event dictionaries (Control, DependencyObject, etc) and are best extended in this way.

Like extension methods today, it is possible to declare and consume these extension members using any .NET language (even those that do not support extension methods/members) and with any CLR version.

Here is the code:

// Property getters and setters
// Compiler restricts the number of arguments and return types.
// When accessed as a property, the "Get" and "Set" prefixes are omitted just like the
//   "Attribute" suffix is omitted from attribute classes.
// There is no compiler-generated storage mechanism and no "auto" extension properties.

[Extension(ExtensionType.GetProperty)]
public static string GetTrimmedText(this Control control)
{
    return control.Text.Trim();
}

[Extension(ExtensionType.SetProperty)]
public static void SetTrimmedText(this Control control, string value)
{
    control.Text = value.Trim();
}

// Event accessors
// Compiler restricts the number of arguments and the return type must be void.
// When accessed as an event, the "Add" and "Remove" prefixes are omitted.

[Extension(ExtensionType.AddEvent)]
public static void AddMouseTripleClick(this Control control, MouseEventHandler e)
{
    // ... etc
    control.Events.AddHandler("MouseTripleClick", e);
}

[Extension(ExtensionType.RemoveEvent)]
public static void RemoveMouseTripleClick(this Control control, MouseEventHandler e)
{
    // ... etc
    control.Events.RemoveHandler("MouseTripleClick", e);
}

// Static extension members are declared without a "this" argument, and by providing
// an additional parameter to the ExtensionAttribute to say which type will receive the member.
// This usage should work for all kinds of members (not just methods).

[Extension(typeof(Color))]
public static Color FromHwb(double hue, double whiteness, double blackness, double alpha)
{
    // convert HWB to RGB ...
    return Color.FromArgb(...);
}

// Extension constructor
// The return type determines the type for which the constructor is being declared.
// We will probably want some restrictions here for enum types, static classes, etc.
// The name of this member is not used, it is called like `new ReturnType(...)`.

[Extension(ExtensionType.Constructor)]
public static IWidget CreateNativeWidget()
{
    // choose implementation, then...
    return new XWidget();
}

// Extension operator
// Compiler restricts the number and types of arguments and return types.
// We will probably want restrictions for enum types, static classes, generics, etc.
// The name of the member is not used, it is called like an operator.

[Extension(ExtensionType.OperatorAdd)]
public static Vector3 Add(Vector3 left, Vector3 right)
{
    return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}
grwGeo commented 8 years ago

@gafter I am sorry if I am getting more theoretical at a time where more concrete ideas are discussed but I think the following can shed some light on the issues involved.

Equivalence

It helps a lot if we think that Type Extensibility is equivalent to a construct where a normal every-day type (the Extension Type) has a non-optional weak reference to an instance of the type it extends (the Extended Type). This binding of the two types needs to be bundled up in such a way that syntactically an instance of the Extension Type is identified with an instance of the Extended Type, and all the visible members of the Extension Type can be called via that identification.

This identification gives us three features (the first two of which to me are the core purpose of Type Extensibility):

  1. Syntactic merging of members (e.g.myExtendedTypeInstance.MyExtensionTypeProperty), this includes static members as well.
  2. An instance of the Extended Type can be passed as an instance of the Extension Type, all its base types and all its implemented interfaces with appropriate (non-user-defined) casting (e.g. (IMyExtensionTypeInterface)myExtendedTypeInstance or (ExtensionTypeBase)myExtendedTypeInstance). [EDIT: These casts should be implicit where appropriate]
  3. (Not necessary but possible plus it shows how the Extension Type can be used as a normal class) an instance of the Extension Type (if defined out of the context of the Extended Type) can be passed as an instance of the Extended Type, all its base types and all its implemented interfaces with appropriate(non-user-defined) casting (e.g. (IMyExtendedTypeInterface)myExtensionTypeInstance).

Looking at it this way, an extension class can be like any other normal class with its own inheritance chain (both up and down the hierarchy), interface implementations, generic type-variables etc. The only difference with a normal class is that there need to be some limitations due to the binding with the Extended Type (for example there needs to be some limitation in naming members to avoid collisions with members of the Extended Type).

My point is that all scenarios (features and limitations) can be properly studied by implementing them in today's C# language features, via the equivalence described above (the two linked types and a weak reference between them). If a scenario is possible and logically consistent today by this equivalence, it can be and should be included in the Type Extensibility features of the language.

I also agree with @HaloFour that this needs to be done via the CLR, not just compiler deception. I go even further as to state that Type Extensibility should be part of legitimate, academic OOP theory that needs to be properly formalised and that OOP languages should be making an effort to implement it.

Syntax proposals

From this point of view I suggest the following syntax for the class definition (note the keyword extensionof):

public class MyExtensionType : MyExtensionTypeBase, ISomeInterface, 
       extensionof ExtendedType { }

or

public class MyExtensionType extensionof ExtendedType : MyExtensionTypeBase, ISomeInterface { }

or

public class MyExtensionType extensionof<ExtendedType> : MyExtensionTypeBase, ISomeInterface { }

Alternatively extensionof can be used with <> or ( ). The point of this syntax is that other than the extensionof<ExtendedType> signal, the definition of MyExtensionType is like any normal class. And this signal just tells the compiler that this class needs a weak reference to an instance of the Extended Type.

Another proposal is the keyword extension to point to the instance of Extended Type that the extension refers to from within the MyExtensionType class (similar to the base or this keyword).

Constructors and Operators

Constructors and Operators are quite interesting because they are members that are shared between the Extension and Extended Type (i.e. unlike an extension property their call is identical e.g. new ExtendedType(some parameters...) or myExtendedTypeInstance1 + myExtendedTypeInstance2). This means that some element of overridden and altered behaviour from the original could potentially be introduced.

Given the possibility that the original Extended Type constructors and operators can be called from the Extension Type (e.g. an Extended Type constructor could be called via the extension keyword similarly to base and this constructors calls), three general principles need to be considered:

  1. Allow override of Extended Type's behaviour (i.e. everything goes).
  2. Force preservation of Extended Type's behaviour without allowing extended behaviour (i.e. don't touch constructors and operators).
  3. Force preservation of Extended Type's behaviour but allow extended behaviour (i.e. yes, but...).

The first gives more freedom and leaves the developers (both creators and consumers of extensions) to deal with consequences. The advantage here is that the option to preserve is still available. The second means constructor and operator extensions are not allowed. The third means for example that when a constructor whose signature matches an original constructor is called then the original constructor is force-called to create the referenced Extended Type instance but no access to that instance is given during construction to avoid altering state and behaviour (i.e. the extension reference will not be available). New constructors and operators (that don't match original ones) are freely allowed in this case.

Without totally rejecting 1 and 2 it seems that 3 is closer to the idea behind Type Extensibility i.e. extending a pre-existing type's state and functionality without interfering with its original behaviour.

Case studies can be i) the Visual Studio designer working with extended controls or ii) the compiler and framework working with extended primitives (e.g. extended strings) or iii) the framework working with extended classes in general or iv) an attempt to recreate WPF in WindowsForms with extended controls.

Hope this is of some help.