Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional arguments in interface without any default value

I was surprised that C# uses a value for optional method argument of interface, not from class implementing this interface. For example:

using System;
                
public class Program
{
    private static IMyInterface instance;
    
    public static void Main()
    {
        instance = new MyClass();
        
        instance.PrintOpt();
        ((MyClass)instance).PrintOpt();
    }
}

public interface IMyInterface
{
    void PrintOpt(bool opt = false);
}

public class MyClass : IMyInterface
{
    public void PrintOpt(bool opt = true) 
    {
        Console.WriteLine($"Value of optional argument is {opt}");
    }
}

produces output:

Value of optional argument is False

Value of optional argument is True

My question is: is it possible to define an optional parameter in an interface without default value or "overridable", so calling of method on instance saved in variable of interface type uses a optional value defined in a class implementing this interface?

like image 447
Dominik Palo Avatar asked Dec 23 '15 16:12

Dominik Palo


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.

Is it mandatory to specify a default value to optional parameter?

OptionalAttribute parameters do not require a default value.

Are optional parameters bad practice?

The thing with optional parameters is, they are BAD because they are unintuitive - meaning they do NOT behave the way you would expect it. Here's why: They break ABI compatibility ! so you can change the default-arguments at one place.

How do you pass an optional argument in Python?

You can define Python function optional arguments by specifying the name of an argument followed by a default value when you declare a function. You can also use the **kwargs method to accept a variable number of arguments in a function. To learn more about coding in Python, read our How to Learn Python guide.


1 Answers

This wouldn't be surprising if you understood how optional arguments are handled internally: they are inlined during compilation.

In other words, at the place where a method is called, any optional arguments are passed by the compiler - if you're calling an interface method, the compiler has no idea that there's an implementation with a different optional argument. The difference is best seen with code like this:

IMyInterface interface = new MyClass();
MyClass theClass = (MyClass)interface;

interface.PrintOpt(); // false
theClass.PrintOpt(); // true

Which is compiled to this (translated back to C#):

interface.PrintOpt(false);
theClass.PrintOpt(true);

The "default" arguments are no longer "default" in the IL code - they are just another explicitly passed argument.

If you want to use optional arguments that are overridable, just use method overloads. Or better, use default values that don't mean anything (e.g. null or default(int?)) and do any replacing for defaults inside of the method. This is in line with the original reason for including optional arguments to C# in the first place - VB-style COM interfaces often have methods with dozens of arguments, almost all of which are optional. Until now, when you wanted to call a method like this, you had to do something like

comInterface.MyMethod(TheActualArgumentICareAbout, Type.Missing, Type.Missing, 
                      Type.Missing, Type.Missing, ...);

Now you can just do

comInterface.MyMethod(argument, anotherSuperUseful: true);

This distinction is a big deal - it also means that you shouldn't ever change default arguments on any public method. Anyone using your library without recompiling will still use the old default value. It's similar to how const values or enums are handled. If you use a null for a default instead, the actual default value will be inside the method itself, and all callers will "see" the correct default even if they don't recompile (similar to using a public static readonly field instead of const, or a class with properties instead of an enum).

like image 68
Luaan Avatar answered Oct 22 '22 23:10

Luaan