Skip to content

Language Feature: Extension Everything #11159

Closed
@gafter

Description

@gafter

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:

  • Instance fields not permitted (at first)
  • Constructors not permitted (at first)
  • Events not permitted (at first)
  • The base clause cannot add interfaces
  • No members may be virtual, override, abstract, sealed, etc.
  • Private helper members (e.g. _flattenCount above) work the same as extension members, even though not accessible outside.
  • Operators will require some language constraints on built-in types, interfaces, etc. For example, the extended type must be either the source or target of a conversion operator.
  • No instance auto-properties (until we support instance fields).

Substantial LDM design work will be required

  • What is the syntax?
  • What is allowed and not allowed? Extending int[]?
  • We will need to describe how we go from a member access e.M to the set of extensions that might be designated by the access.
  • Every construct that can use one of these will have to have its spec amended
    • Member access, method overload resolution
    • Indexing
    • Every kind of operator (e.g. what are the constraints at the declaration, where do we look on the use)
    • Later, constructors
  • For conversions, what limitations do we need to not run into trouble?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions