Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interface implementation with optional arguments

Take this interface:

interface ILogger
{
    void Store(string payload);
}

And this class implementation of ILogger:

class Logger : ILogger
{
    void Store(string payload, bool swallowException = true)
    {
        ...
    }
}

I would anticipate the compiler would recognize swallowException as an optional argument, and thus satisfy the requirements of the interface. Instead, what happens is the compiler complains that Logger does not implement interface member Store.

Another interesting thing I tried was implementing the interface explicitly, like so:

class Logger : ILogger
{
    void ILogger.Store(string payload, bool swallowException = true)
    {
        ...
    }
}

The compiler gives a warning "The default value specified for parameter 'swallowException' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments." It seems to suggest optional arguments are somehow incompatible with explicit interface definitions, but why?

I can work around the problem by overloading Store with two separate function definitions (the way of doing things before optional arguments existed). However I like optional arguments for their syntactic clarity and would prefer that this just worked the way I expect.

I understand there's probably a reasonable (historical or otherwise) explanation for why this is the way it is, but I can't seem to figure it out.

like image 490
James Jones Avatar asked May 07 '15 15:05

James Jones


People also ask

Can we have optional parameter in interface?

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.

How would you implement optional parameters?

To implement the optional parameter first you need to add System. Runtime. InteropServices namespace in your program, then creates an optional parameter using the Optional keyword enclosed in square brackets before the definition of the parameter in the method. The default value of OptionalAttribut is zero.

What is optional argument?

Optional arguments enable you to omit arguments for some parameters. Both techniques can be used with methods, indexers, constructors, and delegates. When you use named and optional arguments, the arguments are evaluated in the order in which they appear in the argument list, not the parameter list.

Does Go support optional parameters?

Go doesn't support optional parameters , default values and function overloading but you can use some tricks to implement the same. Sharing one example where you can have different number and type of arguments in one function.


1 Answers

Because optional arguments in C# are just syntactic sugar.

The method definition in your case is

void Store(string payload, bool swallowException)

rather than

void Store(string payload)

Which obviously doesn't match the interface.

The way default arguments work is that the compiler injects the default values into the call of the method. So if you do Store(payload), the compiler will actually emit Store(payload, true). This is extremely important for understanding of default arguments - it's done in compile time of the caller. So if you change the default argument in the callee without recompiling the caller, the caller is still going to use the old default argument.

This also explains the warning you got - since the default value is passed by the compiler explicitly, and you can't call an explicit implementation of an interface without casting to the interface, you're not going to get an opportunity to use the default value, ever.

You don't actually want to use default arguments at all. Simply define two methods like this:

void Store(string payload, bool swallowException)
{
  // Do your job
}

void Store(string payload)
{
  Store(payload, true);
}

This avoids both of the problems above - the interface contract is satisfied, and the default argument is now part of the callee, not the caller.

Personally, I don't use optional arguments in public API methods at all - they're just aching to cause trouble when you decide that you want to change them at some point. Unless you can make sure they will stay the same forever, don't use them. The same applies to const and enum - both are also determined at compile-time, rather than run-time.

Remember, the reasoning for including default arguments is to allow you to not pass some argument. That makes sense for things like COM API calls (which would otherwise require you to pass all the arguments you don't want to pass as Type.Missing), or null values. Even using false is just asking for trouble when someone decides that a better default would be true - suddenly, some callers are using true and some false, although all think they're using the "default". For a case like yours, I'd use bool? instead, with a default value of null (or default(bool?), whichever you prefer). In the method code itself, you can then easily handle the default at the proper point - say, by doing swallowException.GetValueOrDefault(true).

like image 101
Luaan Avatar answered Oct 15 '22 00:10

Luaan