/* What Exactly Is Dynamic Dispatch? In the following program, you will find two classes, each with a version of a function public void f(). These functions implement different algorithms. If you write A n = new A(); B m = new B(); n.f(); // prints A.f m.f(); // prints B.f No surprise there. But let's understand exactly how the question "which f should be called" is answered. It's answered by TYPE information. In non-object oriented programming languages (e.g. original C, Pascal) types exist only at compile time. Before we use a variable we have to declare its type (String x, int y, etc.) In this case, n is declared to be of type A and m is declared to be of type B. These declarations are seen by the compiler. A is called the "static type" of the variable n and B is the static type of m. The compiler can choose to use this information to determine which version of void f() to call: this is called "static dispatch". In non-object oriented languages, this is the only choice available. But Java was designed for oop to begin with, and in Java there are two notions of type: the static type and the "dynamic type". The word "dynamic" here refers to runtime. That is, when we create an A or B object in memory we add some extra bits of information to record its type. So in addition to the variable(s) int x, each object will also contain information as to whether it's an A object or B object. Why is this runtime notion of type needed in addition to the static type? Because they can be different: A q = new B(); q.f(); // which f will be called? A.f or B.f? In this situation, the declared type of q is A. This is what the compiler sees: the *static* type of q is A. But the *dynamic* type of the actual object in memory that q points to is B. This information is only available at *runtime*. JAVA WILL USE THE DYNAMIC TYPE INFORMATION TO DETERMINE WHICH version of the function to call. So calling q.f() above will print B.f. This is called *dynamic dispatch*. You might ask, why can't the compiler also see that the object assigned to q is a B object? Because in general situations it can't be known, and it can also change: if (Math.random()>0.5) q = new A(); else q = new B(); q.f(); // which version of f will this call? You would have to have supernatural powers to answer the above question STATICALLY, without actually RUNNING the program. And it's not just when random numbers are used: you could test a variable with a value that's determined by user input, which obviously can only be determined at runtime. The compiler will not even try to guess the actual types of objects at runtime. Java uses dynamic dispatch EXCEPT in the following cases: 1. private methods 2. static methods and variables. ("static" here refers to allocation) 3. instance variables. 4. when two functions of the same name exists, but take different arguments: this is called "overloading". In these cases the static type is used to disambiguate the reference at compile time. But these are mostly design choices and other oop languages may behave differently (Kotlin, for example, allows dynamic dispatch on instance variables as well). In C++, dynamic dispatch is only available if you label the superclass methods as 'virtual', and then only use pointers to objects and not stack-allocated objects. You would also need to use public inheritance instead of private inheritance in order to have the same behavior as Java. */ // Where does dynamic dispatch occur in Java? class A { public int x = 1; public void f() {System.out.println("A.f");} protected void p() {System.out.println("A.p");} private void g() {System.out.println("A.g"); } public void pg() { p(); g(); } // which p and g will this call? public static void s() { System.out.println("A.s"); } // overloading: public void h(A n) { System.out.println("h called on A"); } public void h(B n) { System.out.println("h called on B"); } } class B extends A { public int x = 2; public void f() {System.out.println("B.f");} protected void p() {System.out.println("B.p");} private void g() {System.out.println("B.g"); } public static void s() { System.out.println("B.s"); } // pg, h inherited } public class dd { public static void main(String[] av) { A m; // m has a static type superclass A // the dynamic type is generally not known at compile time: if (av.length>0) m = new A(); else m = new B(); m.f(); // which version of f? based on the dynamic type of m A n = new B(); // n has static type A, dynamic type B m.pg(); // prints B.p then A.g, dyn. dispatch on protected, not private m.h(n); // which version of h is called? prints "h called on A" System.out.println(n.x); // which x is it referring to? prints 1. n.s(); // prints A.s } } /* Summary: Dynamic dispatch uses the dynamic or runtime type of an object to determine which version of a function to call. Dynamic dispatch in this program only occurred in the call to m.f(). Dynamic dispatch also occurs on protected methods. Dynamic dispatch does NOT occur on instance variables, private methods or static methods. Dynamic dispatch also does NOT occur when "overloaded" functions, i.e, two functions with the same name but taking different types of parameters are called. The version of h called in the above program is determined by the static type of n, not the dynamic type. EXERCISE: In addition to public, protected and private, you can also have an empty qualifier before a method in a class: void ff() {..} These methods behave like public methods, but are only visible in code that's inside the same package. Usually this means they're compiled together. For example, if you javac a.java and b.java, and this definition is in a.java, then it is also visible in b.java. Devise an experiment (extend the above program) to determine if static or dynamic dispatch is used on these kinds of methods. */