Default interface methods and default values for Auto Properties
Asked Answered
E

2

15

Given that an auto property compiles to a get_method, a set_method and a private variable and since C# 8 is introducing default interface methods

Can properties in Interfaces have default implementations?

Especially a get only property?

Endurant answered 10/12, 2018 at 7:4 Comment(12)
that would be an abstraction surely? ie abstract classSalina
please include links to your source...Salina
I think I heard that the "default implementations" are basically extension methods, so probably not.Cutaway
@JohnB See hereCutaway
So wait. We are three Johns here?Endurant
Yes, you accidentally wandered onto johnoverflow :-pCutaway
i think the driver for this is to allow for some kind of multiple inheritance in C#Salina
Bear in mind that these default interface methods are really for augmenting existing interface methods that aren't default. They do not imply any additional storage locations so an auto-property would be right out (you can't have a magical backing field added to objects implementing the interface)Woodenhead
@JohnDemetriou what do you want the properties for? Default implementation methods cover two scenarios - versioning and traits. You can't use them to version properties. You don't need them for traits though as you can specify getter/setter methods and even make them abstract to demand that implementers provide some service to the trait. An ISerializeToBSON could have an abstract Whatever GetState() for exampleYaelyager
@PanagiotisKanavos I asked if you can. If I want them is irrelevantEndurant
@JohnDemetriou it is actually, as default implementation methods are a means to implement two different concepts - interface versioning and traits. You can version interface properties as long as you don't try to store the data to a field. int Weight {get=>0; set {}} compiles in Sharplab.io. That's enough to support versioning. Traits can be implemented as well as long as you don't try to access fields. Auto-properties are a convenience feature, not a different type of propertyYaelyager
@JohnDemetriou to your questions Can properties in Interfaces have default implementations? Yes. Especially a get only property? Yes. Auto-properties? No, but you don't need them for read-only properties anywayYaelyager
Y
10

No and Yes. An interface can't have state but you can define a property with {get;set;}.

Auto properties aren't a special type of property. They are a convenience feature that generates the code needed to store property values in a backing field.

You can specify a default implementation for properties, both for getters and setters. You can try the following code in Sharplab.io

public interface IDimensions
{
    int Height {get;set;}
    int Width {get;set;}
    int Depth {get;set;}

    int Weight { get=>0; set{} }
    int Density { get=> Weight==0?0:Height*Width*Depth/Weight ; }
}

public class Box:IDimensions
{
    public int Height{get;set;}
    public int Width{get;set;}
    public int Depth {get;set;}
}

Versioning

This demonstrates the versioning scenario. Box implemented a version of IDimensions that only included Height, Width.

Weight was added later with a default implementation that returns 0 and ignores writes. Density was added with a default implementation that returns the volume/density of a box, or 0 if there's no valid weight. Box didn't have to change even though the interfade did. Even the code generated by the compiler doesn't show any changes to the Box class.

Classes can replace the default implementations with their own. Nothing prevents Box from adding int Weight {get;set;} in the future.

The default implementations are available only through the interface :

IDimensions box=new Box();
Console.WriteLine(box.Density);

Traits

The other scenario handled by default implementations is traits.

Let's assume I want to add the IDensity trait to any type of item. In most cases, I'd only need the volume and weight of an item to calculate its density :

public interface IDensity
{
    int Density 
    { 
        get 
        {
            var weight=getWeight();
            if (weight==0) return 0;
            return getVolume()/weight;
        }
    }

    abstract int getWeight();
    abstract int getVolume();
}

This trait will return a simplistic density calculation and force the type it's applied to to implement the int getWeight() and an int getHeight() methods:

public class Crate:IDensity
{
    //Dummy numbers
    public int getWeight()=>55;
    public int getVolume()=>100;
}

public class C {
    public void M() {
        IDensity box=new Cake();
        Console.WriteLine(box.Density);
    }
}

Another container could override that implementation with its own. Perhaps the container has a complex shape :

public class WeddingCake:IDensity
{
    public int getWeight()=>5;
    public int getVolume()=>getWeight()/Density;
    public int Density=>2;
}

The Sharplab.io link for this example is here

Yaelyager answered 12/12, 2018 at 9:3 Comment(7)
Athough comprehensive, I feel that it is wrong. In the accepted answer there cites a source from Microsoft that default interface methods would not work with properties because they infer specific instance implementationEndurant
@JohnDemetriou a source that's talking about something completely different - whether fields are added or not. Properties don't imply any kind of storage. They don't specify any kind of implementation. Besides, click the links and see that the code compiles. The feature was available in the experimental compilers that were released over the last year and were only available as manual downloads. The current release contains only those features that were stable enough. And even so, async enumerables need tweeking to compileYaelyager
@JohnDemetriou I should explain that Sharplab.io is the compilers themselves, available in a web site for experimentation.Yaelyager
Oh, I get it now, you are allowed to, as long as you do not try to implement a backing variable for it, or auto property. So yes auto properties cannot have, but properties that will return code or access other properties, are okEndurant
@JohnDemetriou I'm stealing PHP and Java examples for all of this. Java had default interface methods since java 8.Yaelyager
@JohnDemetriou I did answer about the backing field because in the question you explicitly mention auto-properties (not just properties, but this particular kind) and mention the private field. Yeah, sure, you can have properties with default implementations, just not auto-properties with a private field added by the compiler.Maturity
This doesn't actually compile because Box doesn't implement Depth, which makes the answer somewhat misleading because it looks like it's possible to have a default auto property implementation, but it isn't.Giusto
M
8

No.


The proposal says:

Interfaces may not contain instance state. While static fields are now permitted, instance fields are not permitted in interfaces. Instance auto-properties are not supported in interfaces, as they would implicitly declare a hidden field.

(source)

See also the Channel 9 interview A Preview of C# 8 with Mads Torgersen where they talk about Default Interface Implementations among other things.


Default interface methods is not included in C# 8.0 (beta) which was released with Visual Studio 2019 Preview 1. At the time of writing, the default interface methods prototype is still in development. Refer to Champion "default interface methods".

Maturity answered 10/12, 2018 at 8:1 Comment(2)
I did try using .NET Core 3 Preview 1 on Visual Studio 2019 Preview 1, which according to Announcing .NET Core 3 Preview 1 and Open Sourcing Windows Desktop Frameworks supports default interface methods, but could not get it to work.Maturity
Thank you. I looked for something like that and did not find itEndurant

© 2022 - 2024 — McMap. All rights reserved.