Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Interfaces and shareing variables

Discussion in 'Scripting' started by SparrowGS, Mar 13, 2018.

  1. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    So I made a two classes, Unit and Building, and along side with them two interfaces(actually more, but these are in question), ISelectable and IDamageable, i need them both to have the team number as an int, and i need it to point to the same variable on the script that inherits from the interfaces.
    I did a quick google search and it didn't answer my question, i saw some talk about them being different variables internally.

    Code (CSharp):
    1. public interface IDamageable {
    2.  
    3.     int team{get;}
    4.     //whatever else
    5. }
    Code (CSharp):
    1. public interface ISelecteable {
    2.  
    3.     int team{get;}
    4.     //whatever else
    5. }
    6.  
    how does the class handle this?
    unity isn't giving me any errors and as the unit have one "public int team{get;}"

    am i right to assume that it's just pointing to the same variable no matter what?
    like if it get changed by an interaction with one interface, and then the other interface asks for the value, does it know it changed?

    if i havn't made myself clear say so i'll expand some more
    any information on this subject will be highly appreciated.
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    You're probably not getting any errors yet because the compiler hasn't found it to be ambiguous just yet. If you were to do this:
    Code (csharp):
    1.  
    2. public interface IReceiver : IDamageable, ISelectable { }
    3.  
    you (should) receive a warning that you haven't explicitly defined which interface's contract belongs to which method.

    I would strongly suggest you change your design: Either pass the team to the appropriate functions, like TakeDamage(int attackingTeamId) or create a third interface, ITeamable (terrible name).
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    It depends on how you implement it. Implicitly or explicitly.

    Implicitly is that if you have a member that meets the same name/type/shape requirements as the interface's member, the compiler just considers that as the member that the interface uses. If 2 interfaces have members of the same name, they both can implicitly use the same member of the class.

    So if you have:
    Code (csharp):
    1.  
    2. public interface IDamageable {
    3.  
    4.     int team{get;}
    5.     //whatever else
    6. }
    7.  
    8. public interface ISelecteable {
    9.  
    10.     int team{get;}
    11.     //whatever else
    12. }
    13.  
    14. public class ConcreteClass : IDamageable, ISelecteable
    15. {
    16.  
    17.     private int _team;
    18.  
    19.     //implicitly implements both IDamageable.team & ISelectable.team
    20.     public int team
    21.     {
    22.         get { return _team; }
    23.     }
    24.  
    25. }
    26.  
    If you want to do it explicitly though, it'd be like this:
    Code (csharp):
    1.  
    2. public interface IDamageable {
    3.  
    4.     int team{get;}
    5.     //whatever else
    6. }
    7.  
    8. public interface ISelecteable {
    9.  
    10.     int team{get;}
    11.     //whatever else
    12. }
    13.  
    14. public class ConcreteClass : IDamageable, ISelecteable
    15. {
    16.  
    17.     private int _team;
    18.  
    19.     public int team
    20.     {
    21.         get { return _team; }
    22.     }
    23.  
    24.     int IDamageable.team
    25.     {
    26.         get { return _team; }
    27.     }
    28.  
    29.     int ISelecteable.team
    30.     {
    31.         get { return _team; }
    32.     }
    33.  
    34. }
    35.  
    In this scenario, doing it explicitly is sort of a waste of typing. So you probably wouldn't do it.

    You would only use explicit implementation if the name collided with something else, or if both interfaces accessed different fields:
    Code (csharp):
    1.  
    2. public interface IDamageable {
    3.  
    4.     int team{get;}
    5.     //whatever else
    6. }
    7.  
    8. public interface ISelecteable {
    9.  
    10.     int team{get;}
    11.     //whatever else
    12. }
    13.  
    14. public class ConcreteClass : IDamageable, ISelecteable
    15. {
    16.  
    17.     private int _damageTeam;
    18.     private int _selectableTeam;
    19.  
    20.     int IDamageable.team
    21.     {
    22.         get { return _damageTeam; }
    23.     }
    24.  
    25.     int ISelecteable.team
    26.     {
    27.         get { return _selectableTeam; }
    28.     }
    29.  
    30. }
    31.  

    Because it was implicitly implemented.

    If only one member is named 'team' and returns an 'int' and has a 'getter' method on it. Then yes, it'll point at it... regardless of how many interfaces you attach to it that have a member shaped like that.

    If you happened to add a member called team, but it returned a string for instance, the compiler would complain that IDamageable or ISelectable was not implemented yet. Because no member of the class matches the interface.

    If you then added one that was called team that returned an int, but you also had the one that returned a string. You'd get a compiler error saying that team was already a member, and you can't have 2.

    So then you'd have to either not have the string version, or explicitly implement the interface.

    Yep. Since it points to the same member.

    Hopefully what I said clears this all up.
     
    SparrowGS likes this.
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    I would point out though... something like this member though. If they mean the same thing on both IDamageable and ISelectable... maybe you should abstract that. Something like this:

    Code (csharp):
    1.  
    2. public interface ITeamMember
    3. {
    4.     int team { get; }
    5. }
    6.  
    7. public interface IDamageable : ITeamMember
    8. {
    9.  
    10.     void Damage(float value);
    11.  
    12. }
    13.  
    14. public interface ISelecteable : ITeamMember
    15. {
    16.  
    17.     void Select(object selector);
    18.  
    19. }
    20.  
    21. public class ConcreteClass : IDamageable, ISelecteable
    22. {
    23.  
    24.     private int _team;
    25.  
    26.     public int team
    27.     {
    28.         get { return _team; }
    29.     }
    30.  
    31.     public void Damage(float value)
    32.     {
    33.         //do damage
    34.     }
    35.  
    36.     public void Select(object selector)
    37.     {
    38.         //do select
    39.     }
    40.  
    41. }
    42.  
    I don't know what 'team' is though, or if this relationship makes sense in regards to what it's supposed to represent.

    But if it does... yeah, that's how I would do it.
     
    SparrowGS likes this.
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    You can't actually enforce this at the interface level. Interfaces specifically do not deal with implementation.
     
  6. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Yes, very much so, thanks a ton.

    I like this a lot, thanks for the tip.

    I know that, but i need this to be the case if a class is constructed in this fashion.