414

I noticed that with the optional parameters in C# 4 if you specify an optional parameter on an interface you don't have to make that parameter optional on any implementing class:

public interface MyInterface
{
    void TestMethod(bool flag = false);
}

public class MyClass : MyInterface
{
    public void TestMethod(bool flag)
    {
        Console.WriteLine(flag);
    }
}

and therefore:

var obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

Does anyone know why optional parameters are designed to work this way?

On one hand I suppose the ability to override any default values specified on the interfaces is useful though to be honest I'm not sure if you should even be able to specify default values on the interface as that should be an implementation decision.

On the other hand, this disconnect means you can't always use the concrete class and the interface interchangeably. This of course, wouldn't be a problem if the default value is specified on the implementation, but then if you're exposing your concrete class as the interface (using some IOC framework to inject the concrete class for instance) then really there's no point having the default value as the caller will have to always provide it anyway.

John Smith
  • 7,243
  • 6
  • 49
  • 61
theburningmonk
  • 15,701
  • 14
  • 61
  • 104
  • 28
    Because they are optional? – Oded Feb 07 '11 at 15:02
  • 2
    But you can cast the object instance to `MyInterface` and call it with the optional parameter: `((MyInterface)obj).TestMethod();`. – Jim Mischel Feb 07 '11 at 15:06
  • 15
    @oded - but if you say this parameter is optional on the contract, why do you allow the implementer to not make it optional? doesn't that just cause confusion to anyone looking to use the contract? – theburningmonk Feb 07 '11 at 15:07
  • 2
    I think in this case you can say that the parameter is optional in implementing, not in calling the implementing methods.When you call the method in the class you have to follow the class rules (the parameter is not optional in the class so you can't call the method without it), and in the second hand when you implement the interface you have to follow the interface rules,so you can override the methods with/without optional parameters. Just an opinion. – Mohamad Alhamoud Feb 07 '11 at 15:18
  • 2
    More detail problem explanation here -> http://geekswithblogs.net/BlackRabbitCoder/archive/2010/06/17/c-optional-parameters---pros-and-pitfalls.aspx – Andrew Orsich Feb 07 '11 at 15:47
  • 1
    Worth noting that this appears to break the [Liscov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) – Liam May 26 '21 at 14:39

7 Answers7

275

UPDATE: This question was the subject of my blog on May 12th 2011. Thanks for the great question!

Suppose you have an interface as you describe, and a hundred classes that implement it. Then you decide to make one of the parameters of one of the interface's methods optional. Are you suggesting that the right thing to do is for the compiler to force the developer to find every implementation of that interface method, and make the parameter optional as well?

Suppose we did that. Now suppose the developer did not have the source code for the implementation:


// in metadata:
public class B 
{ 
    public void TestMethod(bool b) {}
}

// in source code
interface MyInterface 
{ 
    void TestMethod(bool b = false); 
}
class D : B, MyInterface {}
// Legal because D's base class has a public method 
// that implements the interface method

How is the author of D supposed to make this work? Are they required in your world to call up the author of B on the phone and ask them to please ship them a new version of B that makes the method have an optional parameter?

That's not going to fly. What if two people call up the author of B, and one of them wants the default to be true and one of them wants it to be false? What if the author of B simply refuses to play along?

Perhaps in that case they would be required to say:

class D : B, MyInterface 
{
    public new void TestMethod(bool b = false)
    {
        base.TestMethod(b);
    }
}

The proposed feature seems to add a lot of inconvenience for the programmer with no corresponding increase in representative power. What's the compelling benefit of this feature which justifies the increased cost to the user?


UPDATE: In the comments below, supercat suggests a language feature that would genuinely add power to the language and enable some scenarios similar to the one described in this question. FYI, that feature -- default implementations of methods in interfaces -- will be added to C# 8.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    now that you put it like that, it doesn't make sense for there to be a restriction on the implementing class to follow the use the same default value as the interface. – theburningmonk Feb 07 '11 at 17:37
  • I never thought of how much pain it could cause that. I guess the only way to make it feel like the interface methods has optional arguments that are equal in any implementation, is to have extension methods in the interface that handle the overloads – Fede May 12 '11 at 17:04
  • 5
    Would there be any possibility of a future .net allowing an interface definition to specify "default" implementations? It would seem conceptually straightforward: create a couple static generic class with some special metadata to hold the methods, and when building the interface vtable for a class which implements the interface, fill any missing spots with the corresponding ones in the appropriate "default methods" class. The fact that struct methods pass 'this' by reference while class methods pass 'this' by value could be dealt with by having one static class for structs and one for classes. – supercat Jan 12 '12 at 23:12
  • 11
    @supercat: We don't have any plans to do so, but a feature like that is possible. It's been proposed before. During the design process for C# 4 we kicked around a lot of what we called "extension everything" features -- we have extension methods, so what would it mean to have extension events, extension properties, extension constructors, extension interfaces, and so on. Classes that you could "attach" to interfaces and say "these methods are the default implementations of this interface" are one possible way to characterize "extension interfaces". An interesting idea. – Eric Lippert Jan 13 '12 at 00:19
  • Extension methods are just compiler sugar; one advantage of having the CLR recognize 'default interface methods' would be that it would allow members to be added to interfaces without breaking existing implementations. For example, one could add a Sort method to `IList`, and have it by default call a Sort implementation that would access and swap elements by index, but have `List` implement `IList.Sort` using its own Sort method. I'm not sure what would be necessary to avoid accidentally implementing a newly-created interface member using a member that wasn't originally... – supercat Jan 13 '12 at 00:39
  • ...an interface implementation. One thing I like about vb.net is that it's clear which members are interface implementations and which members aren't. – supercat Jan 13 '12 at 00:39
  • Actually, a better usage would be if one could add e.g. a covariant `IReadableList` interface, and have `IList` implementations by default implement the indexed read-only property by calling the 'get' half of the indexed read-write property. – supercat Jan 13 '12 at 13:39
  • @EricLippert: Are you saying that the view taken by the compiler team was that changing an existing method argument to be optional wasn't felt to be enough to cause a breaking change in the interface definition? Makes sense. – Richard Ev Apr 18 '12 at 10:17
  • 6
    Still seems counter-intuitive to me. I would think if the interface has an optional parameter it would require the implementing classes to have the same optional parameter. Since optional parameters is principally the same as providing a version with and a version without that parameter the implementing class could choose to implement two explicit versions instead. And if a parameter in an existing interface were desired to make optional, create an additional version without the parameter. The class again could choose 1 with optional or 2 separate. Much more intuitive I think. – Stefan de Kok Oct 26 '12 at 19:15
  • 25
    to clarify my reasoning for why I think it is non-intuitive: to me an optional parameter is "optional to the caller of the method" NOT "optional to the implementer of the interface". – Stefan de Kok Oct 26 '12 at 19:20
  • 14
    "Are they required in your world to call up the author of B on the phone and ask them to please ship them a new version[...]?" No, no phone calls required. B should simply no longer be able to be considered an implentation of MyInterface and the author of D could be made aware of that by the compiler. The author of D would be required to implement D with a TestMethod that accepts a default parameter since that is what the Interface author requires - you are arguing against allowing the interface author to enforce a constraint because someone might want to break it. That is not a good argument. – philofinfinitejest Feb 27 '13 at 20:48
  • @cptphil: Your suggestion is discussed in the latter half of my answer. As I note, it adds *inconvenience* without also adding any corresponding *power*. More generally though: an interface describes *what features are available*, not *how those features are to be exposed by the implementer*. C# gives implementers broad lattitude in how they choose to fulfill the contract of an interface. That's by design; an interface is the servant of an implementer, not its master. – Eric Lippert Feb 27 '13 at 21:03
  • 9
    @EricLippert In the case where the optional parameter is being specified for coding convenience, yes, enforcing inconvenience in the implementation is counter-intuitive. But in the case where the optional parameter is being used to minimize method overloading, a powerful feature, those optional values may take on great significance and ignoring them certainly dilutes that power. Not to mention the case where the concrete implementation specifies a different default value than the interface. It just seems like a very odd disconnect to allow. – philofinfinitejest Feb 27 '13 at 22:01
  • 14
    I agree with @philofinfinitejest here. An interface tells what something can do. If I am passed an implementation of an interface with a different default value than what the interface specifies, how am I to know that? Hey, I have an interface that passes true as a default, so why is this thing getting a false? That, would seem like I did NOT get the interface that I expected. Even worse, I now have to program to an implementation and not an interface. – aaronburro May 16 '14 at 16:49
  • 2
    @aaronburro: There are of course pros and cons to every design decision; if there weren't then the decision would be easy. The C# design team rejected the "optional arguments" feature for *years* because of these sorts of concerns, but the feature was so heavily requested from users, and so useful when dealing with legacy object models designed for languages that have historically had this feature (VB), that the design team decided to go for it despite the entirely reasonable objections you and phil raise. These were not the largest objections raised either! There were many hard decisions. – Eric Lippert May 16 '14 at 17:07
  • 2
    @EricLippert, An issue I just ran into (which led me to this post) was that the implementing class may elect to provide a different default value as well. I would actually expect the compiler to require not only the same default parameters, but also the same default values. You could very easily run into unexpected behavior if `MyClass` defined the method as `public void TestMethod(bool flag=true){...}`. – gregsdennis Sep 05 '14 at 18:06
  • 3
    What's really confusing is `IMine mine = new Mine(); mine.Explode();` where `IMine` defines `Explode(bool destroyNearbyMines = false)` and `Mine` defines `Explode(bool destroyNearbyMines = true)`. Which one takes precedent? The interface's default value or the implementations? I'm of the opinion that default values in the interface shouldn't be violated by an implementation. I find this ambiguous, though. ([IDEOne example](http://ideone.com/U3qqbc)) – crush Dec 15 '14 at 18:55
  • 2
    @crush: C# uses the *compile time type* to solve overload resolution problems at compile time, so in your example it would use the interface. – Eric Lippert Dec 15 '14 at 19:05
  • 1
    @EricLippert Sorry, that was meant as a rhetorical question to make my point that I feel it can become ambiguous to the developer which default value they are specifying. More precisely, it can become ambiguous which default value they are supposed to specify. Any intelligent IDE would tell them that if they had a reference of type `IMine`, then the default value is `false`. However, it won't tell them what the default value is supposed to be according to the implementation of `Mine` (because it doesn't know which implementation is being used). And that's why default values are a problem. – crush Dec 15 '14 at 19:24
  • 4
    @crush: You will get no argument from me that default values produce many bizarre situations; I've written quite a bit about this on my blog. The C# team resisted adding them to the language for over a decade because of these bizarre corner cases, but the requests from users -- particularly users who wanted to use legacy object models designed for use with Visual Basic -- were both numerous and compelling. – Eric Lippert Dec 15 '14 at 19:39
  • I just finished reading your blog post (missed it when I first read the answer somehow). Good stuff. I'm refusing to place default values in any interface I create for this reason. If someone wants to use a default value, then they need an implementation reference type. – crush Dec 15 '14 at 19:49
  • Comment to this answer: so what's the purpose of optional params in interfaces? Shouldn't it be a compiler error if you try to put optional things in interfaces? – Mauro Sampietro Mar 18 '15 at 15:48
  • 3
    @sam: Not having the feature on interfaces would defeat the *entire* point of the feature: easing the burden on C# developers who must use C#-callable versions of COM APIs where the methods have dozens of optional parameters. Those things are all expressed as interfaces in C#. Those scenarios are 99% of the reason the feature was added to C# in the first place; when I was on the VSTO team I heavily lobbied the C# team to add that feature for exactly that reason. – Eric Lippert Mar 18 '15 at 16:23
  • @EricLippert i experienced the same problem when working with office interop. Glad you pointed out. thank you. – Mauro Sampietro Mar 19 '15 at 08:15
  • @supercat: Re: your 2012 comment about default interface implementations. Rumor has it that this is being considered for C# 8. I've been using default interface implementations in Java, and it is one of the few areas where I think Java does a better job than C#. It would be great if this feature could make it in to C# 8. – Eric Lippert Feb 11 '19 at 19:39
  • @EricLippert: Is the feature intended as static sugar to have the compiler bake in default implementations, or are there plans to have the Framework auto-create implementations for classes that don't have them. I don't really see the former as all that valuable, and would worry that it might conflict with the latter if the maintainers of .NET ever get around to implementing it. What I'd like to see would be a means via which an interface `IFoo` could specify that any class that implements of `IBar` should also be considered an implementation of `IFoo`. – supercat Feb 11 '19 at 20:36
  • @EricLippert: I think that could be done, without breaking binary compatibility, by saying that when an attempt is made to use a type (e.g. `thisStruct`) as an unsupported interface type, it will search the type's attributes for any interfaces that are marked as auto-extending, and for each member added in the new interface, auto-generate an implementation like `double newInterface foo(int param1) { return newInterface.oldInterface.structWrap_foo(ref thisStruc it, param1); }`. Having language support as well would be nice, but... – supercat Feb 11 '19 at 20:49
  • ...the ability to e.g. have a function accept an argument of type `IExtendedEnumerable` but be able to receive references to class types that don't include implementations of that interface but do implement `IEnumerable` would seem more valuable than any syntactic sugar a compiler might try to add. – supercat Feb 11 '19 at 20:52
  • @supercat: I don't know what the details are; I'm not keeping up with the day-to-day happenings on the C# team anymore, sadly. Try checking the github forum. – Eric Lippert Feb 11 '19 at 20:59
50

An optional parameter is just tagged with an attribute. This attribute tells the compiler to insert the default value for that parameter at the call-site.

The call obj2.TestMethod(); is replaced by obj2.TestMethod(false); when the C# code gets compiled to IL, and not at JIT-time.

So in a way it's always the caller providing the default value with optional parameters. This also has consequences on binary versioning: If you change the default value but don't recompile the calling code it will continue to use the old default value.

On the other hand, this disconnect means you can't always use the concrete class and the interface interchangeably.

You already can't do that if the interface method was implemented explicitly.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
33

Because default parameters are resolved at compile time, not runtime. So the default values does not belong to the object being called, but to the reference type that it is being called through.

Olhovsky
  • 5,466
  • 3
  • 36
  • 47
7

Optional parameters are kind of like a macro substitution from what I understand. They are not really optional from the method's point of view. An artifact of that is the behavior you see where you get different results if you cast to an interface.

Ariel Arjona
  • 172
  • 1
  • 10
2

Just want to add my take here, as the other answers do provide reasonable explanations, but not ones that fully satisfy me.

Optional parameters are syntactic sugar for compile-time injection of the default value at the call site. This doesn't have anything to do with interfaces/implementations, and it can be seen as purely a side-effect of methods with optional parameters. So, when you call the method,

public void TestMethod(bool value = false) { /*...*/ }

like SomeClass.TestMethod(), it is actually SomeClass.TestMethod(false). If you call this method on an interface, from static type-checking, the method signature has the optional parameter. If you call this method on a deriving class's instance that doesn't have the optional parameter, from static type-checking, the method signature does not have the optional parameter, and must be called with full arguments.

Due to how optional parameters are implemented, this is the natural design result.

Harshdeep Singh
  • 305
  • 1
  • 4
1
var obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

Use

MyInterface obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

and both result in false

Jim K
  • 89
  • 7
1

Thanks for your explanation @eric-lippert

Here is some code example:

[Fact]
public void TestOptionalMethodArgument()
{
    var implementation = new TestHello();
    IHello @interface = implementation;

    Assert.Equal(23, @interface.Action());
    Assert.Equal(40, implementation.Action());
}

public class TestHello : IHello
{
    public int Action(int number = 40)
        => number;
}

public interface IHello
{
    int Action(int number = 23);
}
robie2011
  • 3,678
  • 4
  • 21
  • 20