Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What function will be called?

Tags:

c#

interface

Previously I have asked a question that was answered not fully, hence I have decided to re-formulate my question to understand what is going on:

Here is my class hierarchy:

interface I
{
    void f();
}

class A : I
{
    // non virtual method
    public void f()
    {
        Debug.Log("---->> A ");
    }
}

class B : A
{
    // non overriding but hiding class A method
    public void f()
    {
        Debug.Log("---->> B ");
    }
}

class C : I
{
    // non virtual method
    public void f()
    {
        Debug.Log("---->> C ");
    }
}

Here is the execution code:

Random rnd = new Random();
var randomI = rnd.Next(0, 2);

I i = null;
if (randomI == 0)
{
     i = new B(); 
}
else
{
    i = new C();
}
i.f(); 

As it is right now, it will either output A or C. It won't output B.

Here is the question: Could you please explain how the decision is made what function to call by covering these steps?

  1. When the decision is made what function to call - runtime or compile time?
  2. What is the mechanism how to decide what function to call?
like image 438
Narek Avatar asked Sep 06 '18 12:09

Narek


People also ask

What is a function called?

A function call is a request made by a program or script that performs a predetermined function. In the example below, a batch file clears the screen and then calls another batch file. @echo off. cls.

What is calling function called function?

Calling and Called Function ? The Function which calls another Function is called Calling Function and function which is called by another Function is call Called Function. How does Function execution work? A stack data structure is used during the execution of the function calls.

What happens when you call a function?

Any parameters that the function is expecting are pushed onto the stack frame. They're pushed onto the stack frame in reverse order that they were declared in the called functions parameter list. The return address of the caller function is pushed onto the stack.

Why we use the call function?

The call() method is a predefined JavaScript method. It can be used to invoke (call) a method with an owner object as an argument (parameter). With call() , an object can use a method belonging to another object.


2 Answers

During compile-time it binds a call to I interface, and then during run-time it calls a top method in inheritance chain which implements I.f().

So, in your code this

A a = new A();
a.f();

B b = new B();
b.f();

will make compiler do the following instructions:

  • create an instance of class A and assign to "a"
  • take an object assigned to "a" and call the method, which is on the top of inheritance chain and which implements A.f(). it is A.f() itself in this case
  • create an instance of class B and assign
  • take an object assigned to "a" and call the method, which is on the top of inheritance chain and which implements B.f(). it is B.f() itself in this case

which results into "A" and "B".

However, when you make this:

I i;
i = new B();
i.f();

you make it compile the following instructions:

  • declare a variable "i"
  • create a new object B and assign it to "i"
  • take an object assigned to "i" and call the method, which is on the top of inheritance chain and which implements I.f(). It is A.f(), because class B does not implement interface I

At i.f() line it doesn't know that new B() was assigned to i, it could be passed from somewhere else. It just knows that there is some abstract object instance which implements I and it needs to call its f() method.

You can think of new methods like of methods with different name:

public class B : A
{
    // non overriding but hiding class A method
    public void anotherName()
    {
       Debug.Log("---->> B ");
    }
} 

A a = new A();  
a.f();
B b = new B();
b.anotherName();

I i = new B();
i.f(); // this will obviously call the `A.f()` because there is no such method in B

The only difference is that you can't call hidden method for inherited class instance.

like image 147
Yeldar Kurmangaliyev Avatar answered Sep 30 '22 04:09

Yeldar Kurmangaliyev


When the decision is made what function to call - runtime or compile time?

At compile time the compiler determines that A.f is the method to call if someone casts B to I and calls f on it. At runtime it calls that method if an instance of B (vs say an instance of C) is involved. In other words, the key decision is being made at compile time.

Note that if the method was virtual then see @YeldarKurmangaliyev's answer for how it calls the "top method in inheritance chain" (but that isn't the scenario here).

What is the mechanism how to decide what function to call?

The relevant part of the specification is 13.4.5 Interface implementation inheritance:

A class inherits all interface implementations provided by its base classes. Without explicitly re-implementing an interface, a derived class cannot in any way alter the interface mappings it inherits from its base classes.

This is why class B : A shows A but class B : A, I shows B. Since with the latter you are explicitly re-implementing the interface.

Example from the specification (which is basically your scenario):

A class inherits all interface implementations provided by its base classes. Without explicitly re-implementing an interface, a derived class cannot in any way alter the interface mappings it inherits from its base classes. For example, in the declarations

interface IControl
{
    void Paint();
}
class Control: IControl
{
    public void Paint() {...}
}
class TextBox: Control
{
    new public void Paint() {...}
}

the Paint method in TextBox hides the Paint method in Control, but it does not alter the mapping of Control.Paint onto IControl.Paint, and calls to Paint through class instances and interface instances will have the following effects

Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint();          // invokes Control.Paint();
t.Paint();          // invokes TextBox.Paint();
ic.Paint();         // invokes Control.Paint();
it.Paint();         // invokes Control.Paint();

The specification also talks about using virtual (which is a more common solution than explicitly specifying that B implements I):

However, when an interface method is mapped onto a virtual method in a class, it is possible for derived classes to override the virtual method and alter the implementation of the interface.

like image 44
mjwills Avatar answered Sep 30 '22 05:09

mjwills