6

The following interface has no errors in a .Net Core Console application with C#-8.0

interface I
{
    public abstract void f();
    public virtual void g() => Console.WriteLine("g");
    public sealed void h() => Console.WriteLine("h");
}

abstract prevents adding a definition in interface. virtual and sealed necessitate a definition in interface. sealed prevents an implementation of h in derived classes.

Do abstract, virtual and sealed, when used in interfaces, have any other meaning or applications in current implemented version of C# - 8? How and when should they be used in interfaces?

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
Minimus Heximus
  • 2,683
  • 3
  • 25
  • 50
  • 4
    C# 8 introduced default interface members, something that allows all of those things. An interface can provide an implementation for a member that's used if the implementing classes don't have their own implementation. – Panagiotis Kanavos Mar 11 '20 at 16:53
  • This is useful eg in versioning. Before DIMs, adding a new member to an interface would break all classes that implement it, until they also implemented that method. With DIMs, old classes don't have to change when a new member is added. – Panagiotis Kanavos Mar 11 '20 at 16:56
  • 3
    @PanagiotisKanavos I know that. My question is about abstract, virtual and sealed. What do they mean in interfaces? – Minimus Heximus Mar 11 '20 at 16:57
  • That's the answer. They are used with DIMs. Their use is described in all articles that describe DIMs – Panagiotis Kanavos Mar 11 '20 at 16:58
  • 2
    They shouldn't, if you don't specifically need them. [`public`,] `abstract`, and `virtual` are redundant here. All interface members are virtual (abstract == pure virtual) and prior to C# 8.0, they were always abstract. The abstract/virtual distinction (in a class or, now, in an interface) is simply whether or not there's an implementation. `sealed` prevents the method from being explicitly implemented but not from being implicitly implemented, but that shouldn't be the interface designer's concern. – madreflection Mar 11 '20 at 16:58
  • 2
    Have a look at this (https://www.infoq.com/articles/default-interface-methods-cs8/). Hope it answer your doubt. – Alex - Tin Le Mar 11 '20 at 17:00
  • @madreflection what do you mean that "interface members are virtual"? – Alexei Levenkov Mar 11 '20 at 17:07
  • Interface members, by necessity, require vtable entries. That's the pre-8.0 view, though, I realize. Now you can have static members and such. But the public members that represent the interface are virtual. A public member that implements an interface member may not, itself, be virtual but when accessed via an interface reference, it's a virtual call. – madreflection Mar 11 '20 at 17:07
  • @madreflection you said "sealed prevents the method from being explicitly implemented but not from being implicitly implemented". implicit implementation is also impossible with sealed. Trying to do an implicit implementation does not produce an error. But in fact it is not regarded an implementation by compiler. Just an independent function. – Minimus Heximus Mar 11 '20 at 17:10
  • @nano: You're right, my test was improperly done. In that case, `sealed` seems useless because you can't override your `g` method (in an *interface* that implements `I`) any more than you could override your sealed `h` method, and `g` *isn't* marked `sealed`. – madreflection Mar 11 '20 at 17:17
  • 5
    A significant pedagogical problem here was the choice of "virtual". By "virtual" we mean that when you call a method you do not call the method directly; rather you call via some indirect mechanism such as a table lookup. But this is an implementation detail, and a poor description at that. Really what we mean by "virtual" in C# and C++ and other similar languages is *late bound, single dispatch*. That is, the choice of what method to call is determined at runtime -- late -- and the choice is made solely by examining the type of a single argument -- "this". – Eric Lippert Mar 11 '20 at 17:21
  • 4
    If we then apply this to madreflection's statement, it becomes obviously true. "All interface members are late bound single dispatch". They have to be; when you invoke a method of an interface, you don't know *which actual method will be invoked* until runtime, and the exact method you get depends only on the runtime type of *this*. (Leaving aside the new feature of static interface members of course.) – Eric Lippert Mar 11 '20 at 17:22
  • @EricLippert: Thank you for the correction/clarification. – madreflection Mar 11 '20 at 17:23
  • I didn't intend to make a correction; rather, to explain why it is that this terminology is so confusing and how as language designers we could have made different choices that would have been less confusing. Your statement was correct. – Eric Lippert Mar 11 '20 at 17:24
  • 1
    Oh. Then I thank you for confirming it. – madreflection Mar 11 '20 at 17:24
  • @madreflection It seems you say these keywords are `useless` in interfaces. By `useless` do mean, that they have only the effects I mentioned in the question and no other effects or applications beyond that? – Minimus Heximus Mar 11 '20 at 17:47
  • 3
    @nano: That's correct; those keywords are intended to clarify the meaning. Unfortunately we again have a pedagogical problem. Language designers frequently have to decide whether to make these sorts of redundancies *required*, *optional* or *illegal*, and C# does all three. `private` is optional on a member; if it is omitted, you get it anyway. `public static` is required on a user defined operator; if it is omitted, you get an error. And until recently, `virtual` was illegal on an interface member because it was redundant. – Eric Lippert Mar 11 '20 at 18:01
  • @nano: Well, I only said that `sealed` is useless, whereas the others are merely redundant. `sealed` does have an effect in that it prevents the implementing class from providing an implementation, as you pointed out. However, that's entirely contrary to the purpose of interfaces and, indeed, default interface member implementations (the default part, specifically). A sealed interface member implemented by the interface could be achieved by an extension method (even pre-8.0) and that would be more meaningful as to its intent. You'd expect to be able to provide an implementation. – madreflection Mar 11 '20 at 18:02
  • 3
    @madreflection: I am currently reviewing the chapter in a C# programming book on these features and I share your concerns; having been absent from the design process for some time now it is not clear to me how the designers weighed the various options and came up with the compromise position they did. I need to do more research on this. – Eric Lippert Mar 11 '20 at 18:04
  • 2
    @EricLippert: Looking forward to that blog post, too. ;) – madreflection Mar 11 '20 at 18:04

1 Answers1

1

This is from the proposal:

The syntax for an interface is relaxed to permit modifiers on its members. The following are permitted: private, protected, internal, public, virtual, abstract, sealed, static, extern, and partial.

An interface member whose declaration includes a body is a virtual member unless the sealed or private modifier is used. The virtual modifier may be used on a function member that would otherwise be implicitly virtual. Similarly, although abstract is the default on interface members without bodies, that modifier may be given explicitly. A non-virtual member may be declared using the sealed keyword.

It is an error for a private or sealed function member of an interface to have no body. A private function member may not have the modifier sealed.

bolov
  • 72,283
  • 15
  • 145
  • 224