Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

!Lightweight! Default interface members implementation. Primary for backward compatibility of improved BCL interfaces. MINIMAL CLR CHANGES ARE REQUIRED. #222

Closed
dmitriyse opened this issue Mar 3, 2017 · 9 comments

Comments

@dmitriyse
Copy link

dmitriyse commented Mar 3, 2017


THIS IS LIGHTWEIGHT SUBSET OF #52
That can be implemented sooner than #52

  1. Firstly we adds this limited support
  2. Later after CLR improvement we adds Champion "default interface methods" (16.3, Core 3) #52

Interfaces can also define standard implementation based on base contracts elements.

public interface IBase
{
     int MyProperty {get;}
     string MyFormatting{get;}
}

public interface IDerived: IBase
{
      // This is just defaults, we can override this in the base class.
      string GetFormattedProperty()
      {
            //We can use any members of a base class and anything from System.Object!!!!
            return string.Format(MyFormatting, MyProperty);
      }
}

public class SomeImpl: IDerived
{
       public int MyProperty {get;} = 5;
       public int MyFormatting {get;} = "MyProperty={0}";

       // --------- Magic Implicit Insert by C# (hope 8.0) compiler---
       string IDerived.GetFormattedProperty()
       {
             var thisCasted = (IDerived)this;
             return string.Format(thisCasted.MyFormatting, thisCasted.MyProperty);
       }
       //------------------------------------------------------------------
}

This feature will:

  1. Eliminates tons of boiler-plate code
  2. Solve super-strong problem of adding new features to existing BCL contracts, but allowing existing code to not implement new interface members.
    For example with this feature we can easily add IsReadOnly property to IReadOnlyCollection:
    (see proposal https://github.com/dotnet/corefx/issues/16660)
public interface IReadOnlyCollection<T>
{
    bool IsReadOnly{
        get
        {
             // .this is threated by Compiler as an object.
             var mutableCollection = this as ICollection<T>;
             if (mutableCollection == null)
             {
                   throw new NotImplementedException("You should add your implementation.");
             }
             return mutableCollection.IsReadOnly;
        }
    }
}
  1. Even more magic !!! with this feature we can finally get ICollection to be inherited from IReadOnlyCollection without breaking changes.
    (https://github.com/dotnet/corefx/issues/16626)
public interface ICollection<T>: IReadOnlyCollection<T>
{
     // no any member should be migrated to IReadOnlyCollection.
     // So we will have ICollection<T>.Count and IRedOnlyCollection<T>.Count.
}

public interface IReadOnlyCollection<T>
{
      // The same property is defined in ICollection<T>.
      // Default impelmentation will save as from breaking changes. 
      // Existing code that explicitly implements only ICollection<T>.Count 
      int Count 
      {
            get
            { 
                   // .this is threated by the compiler as System.Object.
                   var mutableCollection = this as ICollection<T>;
                   if (mutableCollection == null)
                   {
                         throw new NotImplementedException("You should add your implementation.");
                   }
                   return mutableCollection.Count;
            }
      }
}
@DavidArno
Copy link

DavidArno commented Mar 3, 2017

An existing, championed, proposal already exists for this: Champion "default interface methods"

@dmitriyse
Copy link
Author

Cool!

@DavidArno
Copy link

As I dislike the idea of language features promoting the use of inheritance, much less multiple inheritance, I downvoted that championed proposal. Downvoting this one too, for consistency (nothing personal!).

@dmitriyse dmitriyse changed the title Default interface members implementation !Lightweight! Default interface members implementation. Primary for backward compatibility of improved interfaces. Mar 3, 2017
@dmitriyse
Copy link
Author

dmitriyse commented Mar 3, 2017

Please let split this "Champion" into two proposals.

  1. Lightweight "Default" interface implementations (this proposal)
  2. Full weight interface like class proposal (Champion "default interface methods" (16.3, Core 3) #52)

This proposal does not requires any CLR changes, only C# compiler improvement.
Even if some "lightweight" default implementation requires rocket-engine inside than we can do:

public interface IMyContract
{
    // No any property/method/statics supported here.
    // Saving CLR from changes.

    // This will be injected as explicit implementation by Compiler. CLR will not do anything new.
    public int GetAnswerForEverything()
    {
         return GreatThinker.GiveMeAnwerToEverything();
    }

  
}

public static class GreatThinker
{
      // 42 returner.
      public int GiveMeAnswerToEverything()
      {
          // Artificial intelligence inside.
      }
}

But this #52 proposal turns interfaces to C++ interfaces and bring multiple inheritance hell to C#

@HaloFour
Copy link
Contributor

HaloFour commented Mar 3, 2017

This proposal doesn't solve the main point of the championed proposal, that is to allow an interface in a separate assembly to add a "default" member without breaking any other compiled assemblies containing classes that implement that interface.

@HaloFour
Copy link
Contributor

HaloFour commented Mar 3, 2017

The championed proposal renders this proposal entirely obsolete. The implementation is nearly identical, except that the CLR is responsible for wiring up the static default instead of the compiler. I don't see room for both proposals. And considering that the other proposal is actually already "championed" by a member of the C# design team, I can't imagine that they would consider an alternative that solves fewer problems.

@dmitriyse dmitriyse changed the title !Lightweight! Default interface members implementation. Primary for backward compatibility of improved interfaces. !Lightweight! Default interface members implementation. Primary for backward compatibility of improved interfaces. NO CLR CHANGES ARE REQUIRED. Mar 3, 2017
@dmitriyse dmitriyse changed the title !Lightweight! Default interface members implementation. Primary for backward compatibility of improved interfaces. NO CLR CHANGES ARE REQUIRED. !Lightweight! Default interface members implementation. Primary for backward compatibility of improved BCL interfaces. NO CLR CHANGES ARE REQUIRED. Mar 3, 2017
@HaloFour
Copy link
Contributor

HaloFour commented Mar 3, 2017

This proposal doesn't solve that problem. If the BCL were to add new members to existing interfaces all assemblies containing classes implementing those interfaces would fail until they are recompiled. That requirement makes it largely useless.

@dmitriyse
Copy link
Author

dmitriyse commented Mar 3, 2017

Yes, unfortunately you are right CLR changes are required even for this proposal.
Thank you for pointing.

@dmitriyse dmitriyse changed the title !Lightweight! Default interface members implementation. Primary for backward compatibility of improved BCL interfaces. NO CLR CHANGES ARE REQUIRED. !Lightweight! Default interface members implementation. Primary for backward compatibility of improved BCL interfaces. MINIMAL CLR CHANGES ARE REQUIRED. Mar 3, 2017
@dmitriyse
Copy link
Author

dmitriyse commented Mar 3, 2017

And considering that the other proposal is actually already "championed" by a member of the C# design team, I can't imagine that they would consider an alternative that solves fewer problems.

We can close this proposal. It's just implementation stage of #52

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants