1

I struggle to understand the use of interfaces in C#. This is likely because I come from Python and it isn't used there.

I don't understand other explanations as they don't fully answer my questions about interfaces. e.g. The purpose of interfaces continued

From what I understand, Interfaces tell a class what it can do, not how to do it. This means at some point the class has to be told how to do the methods.

If this is the case, what's the point in interfaces? Why not just have the definition of the method in the class?

The only benefit I see is to keep it clear what classes can/can't do, but at the cost of not DRY code?

I know that Python doesn't need interfaces and I think this limits my understanding, but can't quite figure it out why.

ANTZY21
  • 65
  • 6
  • This isn't so much of an answer but rather a link to something that helped me. I am a python developer that got into C# development and this chapter from Oreilly's Head First Design finally made interfaces click for me: https://www.oreilly.com/library/view/head-first-design/0596007124/ch01.html This probably wont help OP as its been two years since the question was asked, but I hope it helps someone else as much as it did me. – Sam Wolfe Aug 22 '21 at 21:53

2 Answers2

1

It is used in python, in the form (usually) of abstract classes.

The purpose varies, in java they solve multiple inheritance, in python they act as a contract between 2 classes.

Class A does something and a part of that something involves class B. Class B can be implemented in several ways, so instead of making 10 different classes and HOPE they will be used properly, you make them inherit from an abstract class (an interface) and you ensure they MUST implement all the methods defined as abstract. (NOTE IF THEY DON'T IMPLEMENT ANY OF THE METHODS IT WILL CRASH AT BUILD TIME, WHEN YOU INSTALL THE PACKAGE, NOT WHEN YOU RUN IT WHICH IS VERY IMPORTANT IN MIDDLE/LARGE-SIZE PROJECTS).

You also know that ANY class that implements those methods will work with the class that uses it. This sounds trivial, but the business side LOVES it because it means you can outsource part of your code and it will connect and work with the rest of your code.

From what I understand, Interfaces tell a class what it can do, not how to do it. This means at some point the class has to be told how to do the methods.

They actually tell it what it MUST do, as to how they do it we don't care.

If this is the case, what's the point in interfaces? Why not just have the definition of the method in the class?

That is not the point but yes, absolutely you need the definition of the method in the class that inherits from the interface.

Lets give you a more concrete example.

Imagine you have a python framework that runs some tasks. The tasks can run locally (in the same computer where the python framework is running), they can run on a distributed system, by submitting them to some central scheduler, they can run in a docker container, on Amazon Web services .... you get the idea.

All you need is an interface (an abstract class in python) that has a run_task method, as to which one you use is up to you.

e.g:

class Runner:
    __metaclass__ = abc.ABCMeta

    @abstractmethod
    def run_task(self, task_command):
         return


class LocalRunner(Runner):
    def run_task(self, task_command):
        subprocess.call(task_command)

class SlurmRunner(Runner):
    def run_task(self, task_command):
        subprocess.call('sbatch ' + task_command)

Now thge important bit, as you may be asking Why the ^$^$% do I need all these complications? (probably you don't if yopur project is small enough, but there is a breakpoint depending on size where you almost HAVE to start using these things).

The class that uses the runner ONLY needs to understand the interface, e.g. you have a Task class, that class can delegate the execution of the task to the TaskRunner, as to which one is implemented you DON'T care, they are in a sense polymorphic.

class Task:
    def __init__(self, task_runner):
        self.task_runner = task_runner
        self.task_command = 'ls'

    def run_this_task(self):
        self.task_runner.run_task(self.task_command)

And, if you are some programmer your boss can tell you, I need a new class that executes commands on AWS, you apss it a command and it implements a task_runner method , then you DONT need to know ANYTHING about the rest of the code, you can implement this bit as a completely isolated piece (this is the outsourcing part, now you can have a 100 people designign 100 different p[ieces, they don't need to know anything about the code, just the interfaces).

chepner
  • 497,756
  • 71
  • 530
  • 681
E.Serra
  • 1,495
  • 11
  • 14
0
class Cat:
    def meow(self):
        print('meow')

def feed(cat):
    cat.moew()  # he thanks the owner

tom = Cat('Tom')
feed(tom)

C Sharp has the static type system. The compiler needs to know which methods the class has. That's why we must set type for every variable:

def feed(cat: Cat):
    cat.moew()  # he thanks the owner

But what if we have to write code and don't know what exactly type the variable must have?

def feed(it):
    it.thank_owner()

Moreover we have to suppose our function will be used for various classes. Don't forget we must let the compiler know type of each variable! What to do? The solution:

class Pet:  # an interface
    def thank_owner(self):
        raise NotImplementedError()

def feed(it: Pet):
    it.thank_owner()

But what to do with Cat? The solution:

class Cat(Pet):  # inherits the interface Pet
    def thank_owner(self):
        print('meow')  # or self.meow() if we want to avoid big changes and follow DRY rule at the same time

tom = Cat('Tom')
feed(tom)

By the way now we can add new pets easy. We don't have to rewrite our code.

class Dog(Pet):
    def thank_owner(self):
        print('woof')

beethoven = Dog('Beethoven')
feed(beethoven)  # yes, I use the same function. I haven't changed it at all!

Pay attention we created this class later than feed() and Pet. It's important we didn't think about Dog when writing code before. We were not curious about this. However we didn't have problems when we needed to extend the code.

alega
  • 61
  • 4
  • class Pet: # an interface def thank_owner(self): raise NotImplementedError() Your pet interface will crash at runtime, not at build time, which defies the purpose of the interface in the first place. – E.Serra Mar 25 '19 at 16:55
  • Of course at runtime. It's Python! I wanted explain what the interfaces are needed for. – alega Mar 26 '19 at 08:30
  • if you put an abstract class and extend it and NOT implement the abstract method it will crash at build time (the equivalent of compile time in java/C#), the whole point is to make python more like java or C# in that regard (having a compilation step is very good as it enforces typing, python gives you the option but does not force you to). – E.Serra Mar 26 '19 at 09:04