8

This question really is kinda pointless, but I'm just curious:

This:

public sealed class MyClass
{
   protected void MyMethod(){}
}

compiles, but gives a warning

while This:

public sealed class MyClass
{
   public virtual void MyMethod(){}
}

doesn't compile. Just out of sheer curiosity, is there a reason for this?

BFree
  • 102,548
  • 21
  • 159
  • 201
  • 9
    I'd give an answer, but for some reason I think JS would have a better one. Hmm. – Sam Harwell Jul 21 '09 at 02:20
  • 2
    Apparently JS is prioritizing SO at THREAD_PRIORITY_BELOW_NORMAL - quick everyone get your answers in while you still can! – cfeduke Jul 21 '09 at 02:29
  • +1 good question, i've never even run into this cause i never even thought of doing this...because it doesn't make any sense ! – Stan R. Jul 21 '09 at 02:58

9 Answers9

12

virtual is used to declare a method/property "override-able".

sealed is used to declare that class cannot be inherited from.

So a virtual method in a sealed class could never be overridden, as the class could never be inherited from. It just doesn't make sense.

protected affects access to a member, it does not declare it "override-able" as virtual does (though it is often used in that manner) and is accordingly not contradictory.

Kevin Montrose
  • 22,191
  • 9
  • 88
  • 137
  • Yes, I understand that. Notice I didn't ask "why doesn't this compile" rather I asked why does this compile. The same way virtual doesn't make sense in a sealed class, protected doesn't either see what I'm saying? – BFree Jul 21 '09 at 02:25
  • I *think* the OP realizes that `sealed` doesn't make particular sense with `virtual` or with `protected`. He's wondering why one "not making sense" item is allowed, while another is not. – Sam Harwell Jul 21 '09 at 02:26
  • @280Z28 I agree... We need Skeeter to explain this to us. – Jason Down Jul 21 '09 at 02:28
  • It's around 3AM in the UK, so Jon is most likely asleep. You'll have to wait until dawn... – R. Martinho Fernandes Jul 21 '09 at 02:30
  • Not only does the CLI allow sealed types to declare new virtual members, but it allows calling non-virtual methods with the `callvirt` IL instruction. Everything we talk about here are C# "limiting" things where it makes sense to, as the underlying byte code isn't enforcing it. – Sam Harwell Jul 21 '09 at 02:31
  • Not only does it not make sense, it is also impossible. Sealed explicitly prevents the overhead of a virtual function call (MSIL 'call' vs. 'callvirt'). – cfeduke Jul 21 '09 at 02:35
  • @cfeduke: `sealed` means the compiler *can* use `call`, it doesn't mean it has to. – Sam Harwell Jul 21 '09 at 02:39
  • The CLI is not responsible for enforcing language rules. You could handwrite CIL if you wanted. – Kevin Montrose Jul 21 '09 at 02:47
  • @Kevin: The CLI enforces many things about virtual methods. For example, they can't be static, and they can't be constructors. Also, abstract and sealed methods *must* be virtual. – Sam Harwell Jul 21 '09 at 02:56
  • @280Z28: Yes, but that's not enforcing C# rules. Things are conflated a bit because C#/CLI have evolved together, but just because C# is enforcing something does not mean the CLI does. That's what I'm trying to convey with my prior comment. – Kevin Montrose Jul 21 '09 at 02:59
  • protected also controls the access from outside the class. Granted, you could get the same behavior by making the ctor private (which is why you get the warning), but the main point is it actually makes a difference. virtual has no other effect than directly contradicting sealed. – Tal Pressman Jul 21 '09 at 03:11
4

I can't see a good reason for this. The protected MyMethod can be called from MyClass, but will never be called from a derived class (because MyClass is sealed). The virtual version is also allowed to be called directly from MyClass, but it is illegal for the method to have an override because you can't derive a class from MyClass...

Jason Down
  • 21,731
  • 12
  • 83
  • 117
4

The only reason I can think of is that sometimes you would need to write protected methods to override other protected methods. The language could have been designed to allow this:

protected override void Foo()

but not this

protected void Foo()

but that might have been seen to be a little hard to follow - it's the absence of override which makes it useless, whereas in the case of

public virtual void Foo()

it's the presence of virtual that is useless. The presence of something "wrong" is probably easier to understand than the absence of something useful.

In this case, being virtual may also have performance implications, whereas making something protected instead of private probably doesn't - so it's a bit more severe.

These are just guesses though really - if we're really lucky, Eric Lippert will give a more definitive answer. He's the one you want, not me :)

Best answer: treat warnings as errors and they're equivalent anyway ;)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Ooh, good point, I didn't think of the case where the sealed class in question is inheriting from a base and overriding a protected member. That could very well be a reason. I actually emailed Eric last night, and he responded saying he'll look into it and get back to me. I'll keep this question open till he does. Thanks Jon. – BFree Jul 21 '09 at 14:04
  • 2
    Hey, I'm just guessing too, guys. The language design notes document that the decision to make introducing a virtual method into a sealed type an error was made on the 18th of October, 1999, but does not give any justification for the decision. I can find nowhere in the notes that justifies why introducing a new protected member ought to be legal. My best guess: this was probably simply an oversight in the first version, and then it became a breaking change to ever fix it. – Eric Lippert Jul 21 '09 at 21:36
  • 2
    @Eric: Out of interest, where is this in the spec? It doesn't appear to be in the introductory part of 10.6 which lists the rules for valid combinations of modifiers. I thought I'd find the rule and then see if it's mentioned in either of the annotated specs... and now I can't find the rule. I can't see it in 10.6.3 either. – Jon Skeet Jul 21 '09 at 22:00
  • Um.... I can't find it either. Clearly this was intended to go into the spec, the rule is right there in the notes. I'll add yet another point to our long list of omissions from the spec. Thanks for bringing it to my attention. – Eric Lippert Jul 22 '09 at 16:42
  • @Eric, could this be a matter of implementation challenges influencing design decisions? It does seem a bit odd as the base classes of a sealed class can have virtual methods, yet the sealed class itself cannot. With that said it would need to ensure all virtual methods are filled in...*(But, I do concede that it's a bit silly looking to read virtual or protected within a sealed class.)* – Jason D Nov 29 '09 at 04:53
2

A sealed class can have protected members via inheritance. When a method is part of a class, it doesn't matter how that method got there.

In the first case, with the protected method on the sealed class, its the same as if the sealed class inherited a protected method. So it compiles.

Out of curiosity, what exactly is the warning given?

abelenky
  • 63,815
  • 23
  • 109
  • 159
  • The warning is: "warning CS0628: 'SimpleTestApp.Class1.foo()': new protected member declared in sealed class." – Jason D Nov 29 '09 at 04:57
2

The error is:

CS0549: 'function' is a new virtual member in sealed class 'class'.

First of all, despite the fact that it doesn't really make sense to include new protected or virtual members in a sealed class, the CLI¹ does allow it. The CLI also allows calling members of a sealed class using the callvirt IL instruction, even though a compiler could freely replace it with the call instruction.

Currently, I can't find anything in ECMA-334 (C# Language Specification) that requires the compiler emit the above error. It appears like a Microsoft's implementation added the error just because it doesn't make sense to include new virtual members in a sealed class.

¹The CLI is a virtual machine, and the C# compiler emits byte code that runs on it. Almost any concept that's illegal in the CLI is also illegal in C# for that reason - but this is a case where C# does a little extra (not that it's a problem).

Edit: It seems to posts getting marked up are explaining why it doesn't make sense to write code like that in the OP. But regarding what rule made it a compiler error they appear to be wrong.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
1

A sealed class cannot be sub-classed, therefore virtual is not an option. Thus error.

This first is a bit silly but valid, thus warning.

Simeon Pilgrim
  • 22,906
  • 3
  • 32
  • 45
0

I'd guess the compiler does some optimizations with sealed classes that are impossible if you have a virtual method declared - "not having a vtable" seems a likely candidate.

That's just a guess, though.

kyoryu
  • 12,848
  • 2
  • 29
  • 33
0

As sealed When applied to a class, the sealed modifier prevents other classes from inheriting from it.

here i am trying to explain you one by one:

public sealed class MyClass
{
   protected void MyMethod(){}
}

it gives you warning because practically it make no sense because after declaring a class as sealed you can't inherits it and as your method is protected so you can't access it outside the class using it's object(and keep also in mind that you can't create a child class of this so you can't use this method by that trick also).So practically it makes no sense to making it protected so compiler gives you a warning but if you make it as public or internal then it will not gives you error because it's useful in that case.

now the second one:

public sealed class MyClass
{
   public virtual void MyMethod(){}
}

as you sealed you class and now you are making your method as virtual so indirectly you are giving a offer to someone to override it and that can be only possible by inheritance and here comes the issue.That you class is sealed so you can't perform inheritance with this class.so that's why with virtual it gives error.

i hope it will help you to understand.

for reference http://msdn.microsoft.com/en-us/library/88c54tsw.aspx

Peeyush
  • 4,728
  • 16
  • 64
  • 92
0

Declaring a new protected member implies an intent to share that member with descendent classes. A sealed class cannot have descendents, so declaring a new protected member is a bit of an oxymoron, just as declaring a new virtual method in a sealed class.

As for why virtual produces an error while protected only produces a warning, I can only speculate that perhaps it has to do with the fact that new virtual methods require the compiler to build data structures for the type (a vtable), whereas new protected members only have an access flag set - no new data structure. If the compiler is prohibited from creating a vtable for a sealed class, what should it do if it encounters a new virtual method? Fail the compile. A new protected method in a sealed class is pointless but doesn't required the compiler to venture into forbidden territory.

dthorpe
  • 35,318
  • 5
  • 75
  • 119