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.
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.
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.
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.
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.
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With