Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Interfaces... why?

Discussion in 'Scripting' started by khanstruct, Jan 27, 2019.

  1. khanstruct

    khanstruct

    Joined:
    Feb 11, 2011
    Posts:
    2,865
    For the most part, I understand how interfaces work. Yes, I get that they allow you implement multiple interfaces in a single class, etc. What I don't understand is... why?

    I can't pass an interface as a type, I can't call instances of a particular interface, and I can't even define any functionality within the interface. So what's the point!?

    For example: In my game, ALL objects have quite a few, similar traits. Hence I have a BaseObject. From there, I have BaseCreature and BasePlant, both of which inherit from BaseObject. All good so far.

    Now! Some plants and some animals can be "harvested". Plants can produce fruits and other crops, animals can produce wool, milk, eggs, etc.

    The obvious move here would be to create an interface called IHarvestable. In that, I have a function named Harvest(); ...but why?

    Either way, I'm going to have to define and program the Harvest function on both plant and animal classes, so why not just skip the interface and write the functions?

    I've searched everywhere and can't seem to understand the purpose of these things. YES, I understand that classes can implement multiple interfaces, but who cares if they don't actually do anything!?
     
  2. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    862
    Let's say you don't use interfaces, and instead define a Harvest method on both your harvestable plants, and your harvestable animals. What do you do if you need to call Harvest on an object that could be a plant or an animal?

    How about this?

    Code (CSharp):
    1. BaseObject obj = GetObject();
    2.  
    3. HarvestResult result;
    4. if( obj is HarvestablePlant ) {
    5.     var plant = (HarvestablePlant)obj;
    6.     result = plant.Harvest();
    7. } else if( obj is HarvestableAnimal ) {
    8.     var animal = (HarvestableAnimal)obj;
    9.     result = animal.Harvest();
    10. }
    Now let's say you create a Harvestable interface, and define a method Harvest on it. What does the above look like when you've done that?

    Code (CSharp):
    1. BaseObject obj = GetObject();
    2.  
    3. HarvestResult result = (obj as IHarvestable)?.Harvest();
    Interfaces are there when you need to talk to something in a defined way, but you don't want to care what it is you're talking to.
     
    eisenpony likes this.
  3. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    5,343
    Because then you can do this:

    Code (CSharp):
    1. class Barn {
    2.  
    3.     void DoHarvest(IHarvestable thing) {
    4.         thing.Harvest()
    5.     }
    6.  
    7. }
    You can call the Barn's DoHarvest method with any type which implements the IHarvestable interface so has the Harvest() method. So the DoHarvest(animal); and DoHarvest(crop) will equally right despite the fact that they have nothing else in common.
     
    eisenpony likes this.
  4. SparrowsNest

    SparrowsNest

    Joined:
    Apr 6, 2017
    Posts:
    1,999
    Yes you can.
    You define the signature in the interface and the functionality in the implementing class, giving you the freedom to give each class a different logic to the same function.
     
    angrypenguin likes this.
  5. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    26,727
    You can do kinky things such as getting an interface as a component then working with it too.
     
    eisenpony and khanstruct like this.
  6. khanstruct

    khanstruct

    Joined:
    Feb 11, 2011
    Posts:
    2,865
    Hmm, all good answers. Alright, I'll have to mess with this some more.

    Thanks guys. This is probably the most informative answer I've ever gotten on this question.

    So I'm assuming, since I'll also have non-harvestable plants and animals, I'll have to create a new class for the harvestable types?

    Code (CSharp):
    1. public class HarvestablePlant : BasePlant, IHarvestable
    Thanks again!
     
  7. SparrowsNest

    SparrowsNest

    Joined:
    Apr 6, 2017
    Posts:
    1,999
    If they are literally exactly the same besides the fact one can be harvested and the other cannot I'd consider just having a bool like 'canHarvest'.
     
  8. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    26,727
    Yes abstract classes and Interfaces have a very real danger of over-engineering if you haven't fallen foul of their drawbacks. This will definitely happen but that's OK, the experience will allow you to decide when to use them better.
     
    angrypenguin and khanstruct like this.
  9. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,061
    In many languages, even C++, you can do that: in your generic function call p1.harvest();. If input p1 is a type that doesn't have a harvest function, you'll get either a compile or run-time error. That works just fine. It's often called Duck typing.

    An interface is a way of formalizing "this function only works for types with harvest()". Rewriting as doStuff(Harvestable h) means the same thing, but is explicit and you might get better error messages. But as you note, every class using it takes longer to write (you're also now required to write every function from the interface, even if this function only uses one of them).

    Something to note is C# interfaces work the same as base classes. Suppose you have Animal, and Cats, Dogs ... inherit from it. Animal could be a class or an interface It makes no difference. playWith(Animal a) {...} is the same either way.
     
    hippocoder and khanstruct like this.
  10. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    232
    Interfaces are great for modders if the modding system use C# dlls.
    That allow them to replace existing classes with their own so that they can change the behaviour.
     
  11. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,406
    You cant have a thread talking about interfaces vs abstract classes without talking about composition.

    Like Madgvox writes

    inheritance has alot of drawbacks. Interfaces takes care of the problem because you can composite your classes from various components until you are happy.

    You can also take a more component orientated approach using the component system in Unity.
     
    Last edited: Jan 28, 2019
    eisenpony likes this.
  12. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    532
    It is an abstraction and allows you to define what you can call on an implementing class and what type of return value you expect. Even if you only have just a single implementation in your project an interface allows you to use it for Dependency Inversion.

    Also it may help to make your code more testable by replacing an interface implementation with a test implementation.

    However, interfaces are not needed in most cases they are used, but they can help to implement a lot of design patterns which rely on the abstraction they provide. The abstraction also can help to follow design principles, e.g. SOLID.

    Also they provide a natural language contract, and while technically possible to not follow that, you are highly advised to do so (see Liskov Substitution Principle and Open Closed Principle) but as tl;dr; bugs created by violating what a method describes to do by introducing new side effects can lead to some very nasty, unexpected and difficult to find bugs).

    They are a tool and should be used with care as any tool. Use them where fit and to find out where this is follow the links provided as well as the answers given by others in this thread.
     
  13. khanstruct

    khanstruct

    Joined:
    Feb 11, 2011
    Posts:
    2,865
    Yeah, I think my case is a pretty textbook example of when to use an interface.

    I've been programming for years, but I'm mostly self-taught. Therefore, my "real" programmer friends hate looking at my code. It tends to be a mess (but it works!)

    So I know there are other ways I could accomplish all this. This is just me trying to keep my code neat and efficient like them fancy college grads do :cool:
     
  14. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    886
    hippocoder and MNNoxMortem like this.
unityunity