# C# Language Design Meeting for February 28th, 2024

## Agenda

- [Extensions](#extensions)

## Quote of the Day

- "If we just don't make any mistakes it'll be fine"

## Discussion

### Extensions

https://github.com/dotnet/csharplang/issues/5497  
https://github.com/dotnet/csharplang/pull/7179/commits/520a2a40fc5a0fdb572e5f20f593f9eac59a88da

Today we looked over the proposed set of lookup rules for extensions. Much of the meeting was going over the rules as proposed, which I won't reiterate in these notes; they can be found
in the linked pull request commit above. We made a few comments along the way:

* It may be a bit interesting that you can look up extension members without a qualifier when you're within the extension type that contains the members. We think this is fine, as this is
  a new context that gets to redefine what `this` binds to; `this` for such scenarios is not the underlying type, it's the current extension type.
* We think that the proposed form of doing lookup when in an extension type as if the extension type's underlying type is an inheritance relationship is the correct decision.
* Lookup order proved to be a contentious topic. The proposed rules prioritize one type of extension method over the other, but we think that this is likely a mistake. Users may start naturally
  migrating over to the new extensions slowly, and this may cause potential scenarios where the "wrong" version of an extension is picked; there's no clear answer to us whether the old or new
  should win beyond the overload resolution rules that we already have in the language. For example:
  ```cs
  static class Extensions
  {
      public static X ToX<Y>(this IEnumerable<Y> values) => ...
  }

  implicit extension ImmutableArrayExtensions<Y> for ImmutableArray<Y>
  {
      public X ToX() => ...
  }

  // or reverse:

  static class Extensions
  {
      public static X ToX<Y>(this ImmutableArray<Y> values) => ...
  }

  implicit extension IEnumerableExtensions<Y> for IEnumerable<Y>
  {
      public X ToX() => ...
  }
  ```
  For either of these cases, it seems that the best solution is simply to give both `ToX` methods to overload resolution and let it sort out which one is preferred, erroring if neither is
  preferred. The precise details of this, and whether there will be any disambiguation of old vs new as a final tiebreaker, will need to come in a future meeting; what we are certain of at
  this point is that the proposed version, where there is a preference of one version for lookup, isn't workable.
* There are also some disambiguation scenarios that we will need to consider that can't occur today, such as what will happen in the scenario where a simple name binds to both an extension
  property and an old-style extension method. We can likely look to similar scenarios that can occur for instance members in metadata today, but it's a scenario to think about. Example:
  ```cs
  class TableIDoNotOwn : IEnumerable<Item> { }

  static class IEnumerableExtensions
  {
      public int Count<T>(this IEnumerable<T> t);
  }

  implicit extension MyTableExtensions for TableIDoNotOwn
  {
      public int Count { get { ... } }
  }

  // What happens here?
  var v = table.Count; // Let's get a read from LDM
  ```


#### Conclusion

Lookup in extension types should treat the underlying type as if it is the base type of the extension type. We need to go back and redesign the rules for lookup of extension members from
outside of an extension type to mix old and new style extensions.
