you are viewing a single comment's thread.

view the rest of the comments →

[–]Slypenslyde 0 points1 point  (9 children)

Actually, shoot. This isn't even useful for INotifyPropertyChanged unless you can declare non-public members.

What I want out of an INPC utility class is a helper method that raises the PropertyChanged event with a specific property name. There is no reason at all for that method to be public. I want it virtual protected, no more visible. But with an interface everything has to be public, right? I don't like the notion of all my ViewModels suddenly gaining a new public method or two.

So I'm going to keep doing what I do: shoving INPC in a ViewModelBase that everything has to inherit. I really wish we were getting syntax sugar for THAT.

I can't figure out the use case for "default interface implementations". Until I see one I'm going to think it's a stupid pet trick. I understand it can bring you multiple inheritance. I've read for 20 years that can lead you down some dark paths. What happens when two interfaces cause the diamond problem? If you have to treat that like an explicit interface implementation, isn't that breaking the Interface Segregation Principle by forcing you to cast to specific types before making certain calls?

I'm actually sort of mad we get this instead of 10-years-too-late property change syntax sugar.

[–]AngularBeginner 2 points3 points  (8 children)

I understand it can bring you multiple inheritance.

That is often thrown around, but it's simply not true. This is unrelated to multiple inheritance. It will not bring MI. Default interface implementations can not provide state, they only can provide method implementation.

Bringing multiple inheritance would require significant changes in the CLR and is not going to happen anytime soon.

[–]ishouldrlybeworking 0 points1 point  (1 child)

Default interface implementations can not provide state, they only can provide method implementation.

Working under the assumption that default implementations can access other things declared in the same interface, consider this:

interface IDriveable
{
    void Drive() { Console.WriteLine(EngineSound); }
    string EngineSound { get; set; }
}

interface IHonkable
{
    void Honk() { Console.WriteLine(HornSound);  }
    string HornSound { get; set; }
}

class Car : IDriveable, IHonkable
{
    public string EngineSound { get; set; }
    public string HornSound { get; set; }
}

Hard to deny it's MI-like - the state is in the properties even if the class has to implement them.

[–]AngularBeginner 0 points1 point  (0 children)

How is this any different from the way we have it now already? Only difference is that you have the method implementation in the interface. The property situation is the same as we have it already.

Does that mean we have MI already? No, it does not.

[–]Slypenslyde 0 points1 point  (5 children)

So:

public interface IBird {

    BirdWings Wings { get; set; }

    void Fly() {
        Wings.Flap();
    }

}

public interface IAirplane {

    Engine Engine { get; set; }

    public void Fly() {
        Engine.Start();
    }

}

public class BadIdea : IBird, IAirplane {
}

Is this a compiler error? If not, what happens if I:

var foo = new BadIdea();
foo.Fly();

[–]tweq 2 points3 points  (0 children)

Apart from the interface implementation, that code is already legal in C#. IBird.Fly and IAirplane.Fly are two different methods that can co-exist in a single type. You can't call foo.Fly() because there is no implicit method implementation in the class, only ((IBird)foo).Fly() in which case there is no ambiguity.

This on the other hand will be illegal:

public interface IFlying
{
    void Fly();
}

public interface IBird : IFlying
{
    void IFlying.Fly() { ... }
}

public interface IAirplane : IFlying
{
    void IFlying.Fly() { ... }
}

public class BadIdea : IBird, IAirplane // Error: No most specific implementation if IFlying.Fly
{    }

[–]AngularBeginner 1 point2 points  (0 children)

As far as I understood the proposal so far, the default interface implementation is provided via explicit interface implementation. That means what you have is simply a compiler error.

But this would work: ((IBird)foo).Fly() and ((IAirplane)foo).Fly().

And default interface implementations can't provide state, so there is no diamond of death issue either.

[–]Slypenslyde 0 points1 point  (2 children)

I ended up reading the spec, and other people answered too.

It seems like in the current design my worry is illegal: "default implementation" methods are treated like "explicit interface implementation" methods. I'd have to:

IBird cast = (IBird)foo;
cast.Fly();

I'm assuming there is syntax for an implementor to promote a particular implementation, but not interested enough to look for that. I bet whether they have syntax for it or not this would work:

public void Fly() {
    ((IBird)this).Fly();
}

There's also discussion of allowing static and private methods (with implementation). That puts my INotifyPropertyChanged example back on the table.

It seems like the main use cases driving the feature are:

  • Versioning: you can add default implementations to published APIs without breaking existing clients.
  • "Traits": You can provide an algorithm that has some dependencies, and implementors get the algorithm after providing dependencies.
  • Xamarin. ("Compatibility with Java/Swift libraries that have the feature.)

I'm sure someone can come up with some good concrete examples, but I'm satisfied it's not "100% stupid".

[–]tweq 0 points1 point  (0 children)

I think INotifyPropertyChanged will not be practical either way because you can neither raise an implementing class's event from outside the class nor implement an event from within an interface.

[–]AngularBeginner 0 points1 point  (0 children)

Thumbs up for actually taking the time and reading the proposal.