Search Unity

what is the benefit of calling override method with out base and how unity called ?

Discussion in 'Scripting' started by aaadel, Oct 21, 2020.

  1. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    hello I have a question I searched for an answer a lot, but did not find
    what is the point from the override methods if we didn't use base.MethodName
    like that in the example
    we override this method public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) but we didn't use base
    how unity call this overriden method and what is the benefit of the override if you didn't use base

    how PropertyDrawer class know about ItemCodeDescriptionDrawer class and the body of the overriden method ??


    Code (CSharp):
    1. public class ItemCodeDescriptionDrawer : PropertyDrawer
    2. {
    3.  
    4.  
    5.  
    6.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    7.     {
    8.  
    9.         return EditorGUI.GetPropertyHeight(property) * 2;
    10.     }
    11.  
    12.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    13.     {
    14.         EditorGUI.BeginProperty(position, label, property);
    15.  
    16.         if(property.propertyType == SerializedPropertyType.Integer)
    17.         {
    18.             EditorGUI.BeginChangeCheck(); // Start of check for changed values
    19.             // Draw item code
    20.             var newValue = EditorGUI.IntField(new Rect(position.x, position.y, position.width, position.height / 2), label, property.intValue);
    21.  
    22.             // drow item description
    23.  
    24.             EditorGUI.LabelField(new Rect(position.x, position.y + position.height / 2, position.width, position.height / 2), "Item Description", GetItemDescription(property.intValue));
    25.  
    26.  
    27.  
    28.  
    29.  
    30.  
    31.             // if item code values has changed, then set value to new value
    32.             if (EditorGUI.EndChangeCheck())
    33.             {
    34.                 property.intValue = newValue;
    35.             }
    36.         }
    37.  
    38.         EditorGUI.EndProperty();
    39.  
    40.     }
     
  2. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Unity doesn't handle calling overridden methods - that's built into C#.

    The
    override
    keyword is how it knows, not the
    base.MethodName()
    call.
    All the
    base.MethodName()
    call does is run the original method, but it's not needed in an overridden method.

    There's no benefit or detriment.
    When you override a method, it just means "do this instead of the base method", and you still have the option of calling the base method if you need to.
     
    Last edited: Oct 21, 2020
  3. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    ok then how this overriden method get called ?
    because this method and this class does not have any Refrence or instance in other classes to call this overriden method and i did not use it in start or update methods
    here the main question... how unity or c# called this overriden method without me using it ! ?
    to make it more clear
    watch this video


    he create two override method and he didn't use it in start or update methods howover its run!
     
  4. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Overridden methods are called automatically when the parent class calls their original method. You don't need to explicitly call them (though you still can).
    So somewhere in the
    MonoBehaviourPunCallbacks
    class, it has cases where it's calling
    OnConnectedToMaster

    and
    OnDisconnected
    .

    When these methods are called, it is checked if any of them are overridden by any child classes, and if they are, they run those versions of the methods instead, otherwise they just run the methods as they're defined in
    MonoBehaviourPunCallbacks


    Here's a basic example of how it works:
    Code (CSharp):
    1. public class A : MonoBehaviour {
    2.    private void Start() {
    3.       VirtualMethod();
    4.    }
    5.  
    6.    //This method is virtual, meaning if any children of class A overrides it, the child's version of the method will run instead.
    7.    public virtual void VirtualMethod() {
    8.       Debug.Log("This is the base method in class A.");
    9.  
    10.       //Console output:
    11.       //"This is the base method in class A."
    12.    }
    13. }
    14.  
    15. public class B : A {
    16.    //VirtualMethod is still called from class A's Start method.
    17.    //Because class B overrides the method, this version of the method will run instead of class A's version of the method.
    18.    public override void VirtualMethod() {
    19.       Debug.Log("This is the method in class B.");
    20.  
    21.       //Console output:
    22.       //"This is the method in class B."
    23.    }
    24. }
    25.  
    26. public class C : A {
    27.    //When class C calls base.VirtualMethod(), it will run class A's version of the method.
    28.    //Again, VirtualMethod is called automatically from class A.
    29.    public override void VirtualMethod() {
    30.       Debug.Log("This is the method in class C.");
    31.       base.VirtualMethod();
    32.  
    33.       //Console output:
    34.       //"This is the method in class C."
    35.       //"This is the base method in class A."
    36.    }
    37. }
    Here's some resources about method overriding:
    https://www.geeksforgeeks.org/c-sharp-method-overriding/
    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual
    https://www.c-sharpcorner.com/UploadFile/2072a9/method-overriding-in-C-Sharp/
     
    Last edited: Oct 21, 2020
    CandraWi, aaadel and Bunny83 like this.
  5. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    You might look up "how do virtual functions work". The good examples have something like: baseClass A = new subClass(); A.f();, then discuss when and how we'd call baseClass f() or subclass f(). Then they give an example why "use the type of the object, not the type of the reference" is the best way.

    But in practice, I think I've only overridden 3 functions in unity ever, and that was for a very modular series of mini-games.
     
    aaadel and PraetorBlue like this.
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    Inheritance is very important to understand. But in Unity, you'll get so much more done if you can figure out how to properly leverage composition, which Unity's GameObject/Component architecture is designed for.
     
    orionsyndrome likes this.
  7. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    In general inheritance tends to live on the more systemic side of things. If you build a certain framework, or work upon someone else's framework, it is really convenient to rely on tried principles of inheritance and method overrides. Outside of that, true, it's hardly beneficial to anyone. I too very rarely use the keywords virtual and override. Base might popup here and there, but inheritance is meh in Unity in general. Like PraetorBlue said, composition in Unity is much more important.
     
  8. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    thank you for you reply
    the output was always call methods A but it's ok that's what i was looking for
    what if i want to do the same thing in c# console app
    i tried this code but didn't work

    Code (CSharp):
    1. class Program
    2.     {
    3.         static void Main(string[] args)
    4.         {
    5.  
    6.             var a = new A();
    7.             a.VirtualMethod();
    8.  
    9.         }
    10.  
    11.     }
    12.  
    13.  
    14.     public class A
    15.     {
    16.         public virtual void VirtualMethod()
    17.         {
    18.             Console.WriteLine("This is the base method in class A.");
    19.  
    20.         }
    21.     }
    22.  
    23.     public class B : A
    24.     {
    25.        
    26.         public override void VirtualMethod()
    27.         {
    28.             Console.WriteLine("This is the method in class B.");
    29.  
    30.          
    31.         }
    32.     }
     
  9. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    Of course not, because you didn't create an instance of B. You have an instance of A, so only A's method will be called. Try this:
    Code (CSharp):
    1.         static void Main(string[] args)
    2.         {
    3.             A myInstance = new B();
    4.             myInstance.VirtualMethod();
    5.         }
    Notice that the type of the "myInstance" reference is A. But you will see that B's method gets called because the actual type of the object is B.
     
    Vryken likes this.
  10. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    yup i was looking for something like that because out side unity you must ues reference when i tried to use object i can't call the methods inside that instance
     
  11. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    the problem here if i want to make framework and i want class A to be in Inheritance class and i want to call the virtual method in class A from the class who Inheritance A,,, in that case i will not know what the name of the new class is
     
  12. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    i want to do the same idea here but in normal c# console app
     
  13. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    That's the beauty of it. You don't need to know the name of the class. You just call the virtual method on your A reference and it works.
     
    aaadel and Vryken like this.
  14. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    What @PraetorBlue mentioned is correct.
    You have to create an instance of the child class for the overridden method to be called.
    Calling
    A.VirtualMethod
    will just run the method in class
    A
    , because nothing is overriding it.
    However, if you cast an instance of
    B
    as type
    A
    and then call the method...
    Code (CSharp):
    1. A instance = new B();
    2. instance.VirtualMethod();
    ...The
    B
    version of the method will be run, even though
    instance
    is casted as type
    A
    , because it was actually an instance of
    B
    that was created.

    Unless I'm reading this incorrectly, this sounds more like you may want to implement an abstract method, rather than a virtual method.
    In this case, class A needs to be marked as abstract, and the method as well:
    Code (CSharp):
    1. public abstract class A {
    2.    public abstract void SomeMethod();
    3. }
    An abstract method has no body when defined - the body must be implemented by any non-abstract class that inherits from
    A
    :
    Code (CSharp):
    1. public class B : A {
    2.    public override void SomeMethod() {
    3.  
    4.    }
    5. }
    Note that with abstract methods, you cannot call the base method (
    base.SomeMethod()
    ), because there is no implementation where it's defined in its original abstract class.

    See: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract
     
    Last edited: Oct 22, 2020
    aaadel likes this.
  15. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    you didn't understand me
    what if i want to create my own framework and my Framework contain Inhreritance class called A with virtual method and me as developer i want when some one override the virtual method.. call the base method in force without him write base.MethodName()
    same idea in unity example
    i dont know if you got the idea
    sorry for my bad english
     
  16. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    I understand you perfectly well. You can write a function in your framework that accepts a parameter of type A and call a virtual method on it, and the person who is using your framework can write their own class C that extends A and implement their own override. Then your code will happily invoke their override.
     
    aaadel and orionsyndrome like this.
  17. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    this is exactly one of the use cases inheritance was made for.
    you need to learn how inheritance (and method overriding; aka polymorphism) works and what it's solving, regardless of unity.

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism
     
  18. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    yup thats what i mean
    can you give me example
     
  19. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    do you consider the previous examples as not examples enough?
     
  20. aaadel

    aaadel

    Joined:
    May 11, 2019
    Posts:
    18
    my english not good i only understand half
    with code i can Understand more
    Sorry for my many questions
     
  21. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    They're pretty much the same thing. In a base class
    virtual void f() { print("ERROR -- this must be overriden"); }
    isn't an abstract function, but it basically is.
     
  22. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I mean, sure, but if you're going to throw an error to indicate that a virtual method must be overridden at run-time, why not just make it abstract and force it to be overridden at compile-time?
     
  23. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    That's the point -- abstract is just virtual with a nicer error message. Someone wrote that the OP should try abstract instead of virtual. I'm saying don't bother -- it won't change anything important.
     
  24. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    the main differences is that abstract methods
    a) need no method body
    b) get caught at compile-time

    by contrast, virtual void f() { throw } is in run time
    provides default behavior and doesn't need to be overridden

    so even though it might seem like it's the same thing in practice, the differences are huge actually

    but if people normally use sticks and duct tape to implement advance concepts such as polymorphism, then sure, it's all the same. but why bother with any of it then. why don't we just goto here goto there and done.
     
  25. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    RE: abstract vs. virtual: the OP seems to be confused about why inherited classes would want to redefine functions and how dynamic dispatch handles baseClassVariable pointing to subClassObject. Virtual functions are the best for that. Abstract functions (or an interface) is the same explanation, but slightly more complicated. Asking the OP to look at it seems like an unhelpful side-track.

    Sure, in some situations abstract vs. virtual might be a "huge" difference, but not here.
     
  26. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    I wasn't the one mentioning abstract in the first place, and perhaps you're right that it's a side-track, but perhaps it was worth mentioning. And I think it was worth mentioning, because there is no getting to the bottom of this topic anyway, if the OP is unwilling or unable to comprehend the big picture.

    But regardless, given that's already said and done, and that the Road has been shown, I'm not entirely convinced that we now shouldn't discuss where that Road leads, just because OP seems to be confused about his general destination.

    Point being that I don't agree with this statement. It is very misleading in my opinion, and not only the OP will remain confused, but also tainted with dubious half-truths.

    It is much better to say upfront "Do not use abstract, you are unworthy" than "Abstract is the same thing as virtual, it's just bolts are screwed the other way." We're not here to protect OPs from knowing too much.

    By that same account "You can also write Java, it will work as long as it looks just like C#"
     
  27. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    But it's not screwed the other way. Abstract, virtual and interfaces all use exactly the same mechanism. The textbook example:
    Code (CSharp):
    1. void playWith(Animal a1) {
    2.   ...
    3.   float p = a1.price();
    4.   ...
    5. }
    That function will probably have inputs of Cat's, Dog's, Skunk's, and other Animal subclasses. It chooses which price() to call based on the _object_ a1 points to. Finally, if Rat didn't write a price() function, it will search up the class tree in Rodent, Mammal, and finally Animal. You could change Animal.price to/from abstract, or change Animal to/from an interface, and playWith would run the same. Virtual and Abstract functions are handled exactly the same way here.

    If every animal's price is completely different, we could have Animal.price() return a fake value. Then if Rat forget to write their price() you'd get an "error" of -$999999 during a test. We can do better. Leaving Animal.price() blank tells you right away "error: Rat has no price()". That's why I say "abstract is virtual with nicer errors".
     
  28. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    I completely agree with you from the point of pure pragmatism.

    But C# is a statically-compiled language, not interpreted, so it cannot be the same.

    You see, it works completely differently from the perspective of a compiler. Virtual designation is just a permission flag, where the author simply attaches the permission to override the method XY by any derived class. There are no further obligations involved. And the compiler checks if the overrides were permitted or not.

    Abstract designation is a complete compiler feature. As an author of derived classes you have to implement abstract methods, unless your derived class is also abstract. It's not just a permission any more, it's a full contract clause. This is a different kind of a full-on construct for a compiler to be able to appreciate and digest bodyless methods, and then maintain this "abstract" logic further.

    It is more on the side of interfaces, agreed, but still wildly different from virtual.

    Even the four basic principles of OOP highlight this difference:
    - encapsulation (private/public, properties)
    - abstraction (interfaces, default methods, abstract classes/methods)
    - inheritance (classes, derivations)
    - polymorphism (overloads, virtual/overrides, interface hiding, and the upcoming feature of 'roles' that didn't make the cut for C# 9, can't find it anymore, I'm sure they haven't abandoned it because it's really important for how C# treats extensions and extensions on primitives, but they've delayed it massively it seems)

    Though it's not always as clear, and I get that sometimes it's hard to tell if something is a feature of this or that. For a long time, abstraction wasn't even a part of the key principles, and this is how I taught about it back in the 90's, which is weird, and probably the source of all confusion.

    A general guideline would be that polymorphism works more like a game spell would -- turn a man into a rabbit! There aren't any specific physical rules to worry about, only some negotiable framework of ideas, i.e. the rabbit still has to be affected by gravity, you can't wish to have unlimited wishes, that kind of thing. More like pragmatic, down-to-earth, engineering workarounds to academic purity.

    Abstraction is something else, and is always much more rigid in terms of how it's implemented. It's always a strict design-time contract that has to be preemptively checked by a compiler. Abstract classes are more like weird interfaces that allow concrete derivations, instead of having only concrete implementations. And in that sense, they're really one of a kind -- think about it, they exist only in your source code (of course, let's ignore the types, but in terms of that you can't have them static and you can't have an instance of them) -- not even remotely comparable to virtual/override. Also they're a pure symmetry to default methods, which is when you implement a method inside an interface. Also a wild thing.

    I'm sad that we can't have roles soon enough however, that's my #1 anticipated feature. A nice departure from the rigidity of OOP, in fact, moving into something else, a truly polymorphic language, so to speak. They're basically borrowing from and building upon the underlying design of IL, most of which was made to support F#, hence this transition into wild and unexplored territories.
     
  29. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    It's been a while since I looked, but virtual causes the compiler to generate different code. Without it, a1.f() compiles into a basic, fast call to Animal.f(). Virtual adds those "find the real object type" extra lines. It also causes the generation of a table. rat1.f() doesn't actually search through Rat, Rodent, Mammal then Animal at run time -- we figure that out in advance and save things like "Rat.f -> call Mammal.f". An abstract function would trigger the same 2 things, plus the extra "you can't instantiate an abstract class" rule.

    Or imagine Animal has f() abstract, Mammal overrides it, and new we're on Cat. From Cat's point of view, "abstract" f() appears virtual -- we can override or not.

    Concept-wise, I learned that the big idea is having an interface, then the rest follows. If I communicate with B through only these 4 functions, or course the internals of B are encapsulated and I think of B in an abstract way. Polymorphism seems to come later. How can I make safely make several types with the same interface? Inheritance is one way.
     
  30. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    Well, the abstract should work exactly the same as virtual, if you look at the lowered code, but the non-instantiability is not supposed to actually live in runtime. Virtual has to work differently in run time because of the v-tables and late binding.

    However! You are right that abstract does emit code, and actually does live in the runtime, not because that's expected and I'm wrong, but because of another feature -- and this where I learn something new -- reabstraction.

    I don't know if anyone ever used it, but it seems that both Java and C# allow overriding a method as abstract, after it was already marked as virtual by its superclass. Weird, but there you go. In some way, we're both right. Abstract does produce a tangible effect on runtime (apart from acting as virtual, as expected), even though it really shouldn't from the language theory perspective.

    Oh man, at least we learn something new every day.

    So I guess you're technically right, that abstract is virtual "with a nicer error message."
    It shouldn't be like that and is not like that in theory, but implementation details do, in fact, reveal that it behaves exactly like that. In that sense, you win.
     
  31. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    I think this is where madness lies, describing programming concepts based on particular, detailed implementation details. A novice can know a foreach is a shortcut for a for-loop over a list. Later they learn it's done with iterators, and those are a Design Pattern. But a foreach is still a shortcut for a for-loop over a list.

    Likewise a beginner can learn how virtual functions work. Then they can learn an abstract function is a virtual function that you don't define in the base class. The rest follows: of course you can't use a class with an undefined function, and it makes sense to call those unusable base classes "abstract classes". Of course any subclass can override that function (since it's virtual).

    It's even a nice lesson on OOP: programming concepts always work the way you think they should, but the exact way the compiler makes that happen may be very different than what you thought. And that doesn't matter.