10

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?

John Demetriou
  • 4,093
  • 6
  • 52
  • 88
  • that would be an abstraction surely? ie abstract class – jazb Dec 10 '18 at 07:06
  • please include links to your source... – jazb Dec 10 '18 at 07:07
  • I think I heard that the "default implementations" are basically extension methods, so probably not. – ProgrammingLlama Dec 10 '18 at 07:07
  • 2
    @JohnB [See here](https://www.infoq.com/articles/default-interface-methods-cs8) – ProgrammingLlama Dec 10 '18 at 07:09
  • So wait. We are three Johns here? – John Demetriou Dec 10 '18 at 07:10
  • 9
    Yes, you accidentally wandered onto johnoverflow :-p – ProgrammingLlama Dec 10 '18 at 07:12
  • i think the driver for this is to allow for some kind of multiple inheritance in C# – jazb Dec 10 '18 at 07:12
  • 2
    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) – Damien_The_Unbeliever Dec 10 '18 at 07:26
  • @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 example – Panagiotis Kanavos Dec 10 '18 at 11:03
  • @PanagiotisKanavos I asked if you can. If I want them is irrelevant – John Demetriou Dec 10 '18 at 12:26
  • @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 property – Panagiotis Kanavos Dec 10 '18 at 12:44
  • @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 anyway – Panagiotis Kanavos Dec 10 '18 at 12:48

2 Answers2

8

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

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • 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 implementation – John Demetriou Dec 12 '18 at 09:35
  • @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 compile – Panagiotis Kanavos Dec 12 '18 at 09:43
  • @JohnDemetriou I should explain that [Sharplab.io](https://github.com/ashmind/SharpLab) *is* the compilers themselves, available in a web site for experimentation. – Panagiotis Kanavos Dec 12 '18 at 09:46
  • 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 ok – John Demetriou Dec 12 '18 at 09:47
  • 1
    @JohnDemetriou I'm stealing PHP and Java examples for all of this. Java had default interface methods since java 8. – Panagiotis Kanavos Dec 12 '18 at 09:49
  • 1
    @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. – Theraot Dec 12 '18 at 13:03
  • 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. – jsabrooke Aug 04 '22 at 11:34
6

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".

Theraot
  • 31,890
  • 5
  • 57
  • 86
  • 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](https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks/) supports default interface methods, but could not get it to work. – Theraot Dec 10 '18 at 09:21
  • Thank you. I looked for something like that and did not find it – John Demetriou Dec 10 '18 at 10:13