Overloading in Java and multiple dispatch

scala multiple dispatch
haskell multiple dispatch
python multiple dispatch
java multimethod
rust multiple dispatch
java dispatcher pattern
visitor pattern
diagonal dispatch

I have a collection (or list or array list) in which I want to put both String values and double values. I decided to make it a collection of objects and using overloading ond polymorphism, but I did something wrong.

I run a little test:

public class OOP {
    void prova(Object o){
        System.out.println("object");
    }

    void prova(Integer i){
    System.out.println("integer");
    }

    void prova(String s){
        System.out.println("string");
    }

    void test(){
        Object o = new String("  ");
        this.prova(o); // Prints 'object'!!! Why?!?!?
    }

    public static void main(String[] args) {
        OOP oop = new OOP();
        oop.test(); // Prints 'object'!!! Why?!?!?
    }
}

In the test seems like the argument type is decided at compile time and not at runtime. Why is that?

This question is related to:

Polymorphism vs Overriding vs Overloading Try to describe polymorphism as easy as you can

EDIT:

Ok the method to be called is decided at compile time. Is there a workaround to avoid using the instanceof operator?


Overloading in Java and multiple dispatch, This post seconds voo's answer, and gives details about/alternatives to late binding. General JVMs only use single dispatch: the runtime type is only considered  In this article, we will look at the Overloading and Overriding in Java in detail. Yes, in Java also, these are implemented in the same way programmatically. Let us have a look into that one by one. Overloading in Java. When a java class has multiple methods with the same name but with different arguments, we call it Method Overloading. By


What you want is double or more general multiple dispatch, something that is actually implemented in other languages (common lisp comes to mind)

Presumably the main reason java doesn't have it, is because it comes at a performance penalty because overload resolution has to be done at runtime and not compile time. The usual way around this is the visitor pattern - pretty ugly, but that's how it is.

Multiple Dispatch: A Fix for the Problems of Single Dispatch , In this article, we'll first look at Java's single dispatch and Java's overloading and then use what we have learned to understand multiple  In this tutorial,we will learn about the java method overloading and method overriding step by step. Method Overloading. When the class contains multiple methods with the same name but different parameter then it is known as method overloading.


When calling a method that is overloaded, Java picks the most restrictive type based on the type of the variable passed to the function. It does not use the type of the actual instance.

Multiple dispatch, You can do runtime dispatch on multiple argument types. AFAIU in e.g. C++ you can only do that during runtime by the use of virtual functions, which only dispatch  Multiple dispatch vs Function overloading. 13 mins ago . The State of Open Source Security 2020. 14 mins ago . Introducing ClickHouse — The Fastest Data Warehouse


Old question but no answer provides a concrete solution in Java to solve the issue in a clean way. In fact, not easy but very interesting question. Here is my contribution.

Ok the method to be called is decided at compile time. Is there a workaround to avoid using the instanceof operator?

As said in the excellent @DaveFar answer, Java supports only the single-dispatch method. In this dispatching mode, the compiler bounds the method to invoke as soon as the compilation by relying on the declared types of the parameters and not their runtime types.

I have a collection (or list or array list) in which I want to put both String values and double values.

To solve the answer in a clean way and use a double dispatch, we have to bring abstraction for the manipulated data. Why ?

Here a naive visitor approach to illustrate the issue :

public class DisplayVisitor {

    void visit(Object o) {
        System.out.println("object"));
    }

    void visit(Integer i) {
        System.out.println("integer");
    }

    void visit(String s) {
        System.out.println("string"));
    }

}

Now, question : how visited classes may invoke the visit() method ? The second dispatch of the double dispatch implementation relies on the "this" context of the class that accepts to be visited. So we need to have a accept() method in Integer, String and Object classes to perform this second dispatch :

public void accept(DisplayVisitor visitor){
    visitor.visit(this);
}

But impossible ! Visited classes are built-in classes : String, Integer, Object. So we have no way to add this method. And anyway, we don't want to add that.

So to implement the double dispatch, we have to be able to modify the classes that we want to pass as parameter in the second dispatch. So instead of manipulating Object and List<Object> as declared type, we will manipulate Foo and List<Foo> where the Foo class is a wrapper holding the user value.

Here is the Foo interface :

public interface Foo {
    void accept(DisplayVisitor v);
    Object getValue();
}

getValue() returns the user value. It specifies Object as return type but Java supports covariance returns (since the 1.5 version), so we could define a more specific type for each subclass to avoid downcasts.

ObjectFoo

public class ObjectFoo implements Foo {

    private Object value;

    public ObjectFoo(Object value) {
        this.value = value;
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

    @Override
    public Object getValue() {
        return value;
    }

}

StringFoo

public class StringFoo implements Foo {

    private String value;

    public StringFoo(String string) {
        this.value = string;
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

    @Override
    public String getValue() {
        return value;
    }

}

IntegerFoo

public class IntegerFoo implements Foo {

    private Integer value;

    public IntegerFoo(Integer integer) {
        this.value = integer;
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

    @Override
    public Integer getValue() {
        return value;
    }

}

Here is the DisplayVisitor class visiting Foo subclasses :

public class DisplayVisitor {

    void visit(ObjectFoo f) {
        System.out.println("object=" + f.getValue());
    }

    void visit(IntegerFoo f) {
        System.out.println("integer=" + f.getValue());
    }

    void visit(StringFoo f) {
        System.out.println("string=" + f.getValue());
    }

}

And here is a sample code to test the implementation :

public class OOP {

    void test() {

        List<Foo> foos = Arrays.asList(new StringFoo("a String"),
                                       new StringFoo("another String"),
                                       new IntegerFoo(1),
                                       new ObjectFoo(new AtomicInteger(100)));

        DisplayVisitor visitor = new DisplayVisitor();
        for (Foo foo : foos) {
            foo.accept(visitor);
        }

    }

    public static void main(String[] args) {
        OOP oop = new OOP();
        oop.test();
    }
}

Output :

string=a String

string=another String

integer=1

object=100


Improving the implementation

The actual implementation requires the introduction of a specific wrapper class for each buit-in type we want to wrap. As discussed, we don't have the choice to operate a double dispatch. But note that the repeated code in Foo subclasses could be avoided :

private Integer value; // or String or Object

@Override
public Object getValue() {
    return value;
}

We could indeed introduce a abstract generic class that holds the user value and provides an accessor to :

public abstract class Foo<T> {

    private T value;

    public Foo(T value) {
        this.value = value;
    }

    public abstract void accept(DisplayVisitor v);

    public T getValue() {
        return value;
    }

}

Now Foo sublasses are lighter to declare :

public class IntegerFoo extends Foo<Integer> {

    public IntegerFoo(Integer integer) {
        super(integer);
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

}

public class StringFoo extends Foo<String> {

    public StringFoo(String string) {
        super(string);
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

}

public class ObjectFoo extends Foo<Object> {

    public ObjectFoo(Object value) {
        super(value);
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

}

And the test() method should be modified to declare a wildcard type (?) for the Foo type in the List<Foo> declaration.

void test() {

    List<Foo<?>> foos = Arrays.asList(new StringFoo("a String object"),
                                      new StringFoo("anoter String object"),
                                      new IntegerFoo(1),
                                      new ObjectFoo(new AtomicInteger(100)));

    DisplayVisitor visitor = new DisplayVisitor();
    for (Foo<?> foo : foos) {
        foo.accept(visitor);
    }

}

In fact, if really needed, we could simplify further Foo subclasses by introducing java code generation.

Declaring this subclass :

public class StringFoo extends Foo<String> {

    public StringFoo(String string) {
        super(string);
    }

    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }

}

could as simple as declaring a class and adding an annotation on:

@Foo(String.class)
public class StringFoo { }

Where Foo is a custom annotation processed at compile time.

Is multiple dispatch the same as function overloading?, Now Java doesn't supports multiple dispatch as above.The above code is an example of overloading. Overloading vs Multiple Dispatch Method overloading increases the readability of the program. Different ways to overload the method. There are two ways to overload the method in java. By changing number of arguments; By changing the data type; In java, Method Overloading is not possible by changing the return type of the method only. 1) Method Overloading: changing no. of


this isn't polymoprhism, you've simply overloaded a method and called it with parameter of object type

Single Dispatch, Multiple Dispatch, Dynamic Dispatch, Double , Multiple dispatch is not (always) the same as function overloading, although they do bear some similarities. And Java does not support multiple  The problem of the meet example is that it is function overloading and not multiple dispatch. Difference: Function overloading using the static type and not the actual type. Basically meet will always call the function


Multiple Dispatch vs. Function Overloading, The most fundamental difference (I would say) is that overloading (as available in C++, etc.) is a compile-time selection of exactly what function to call, while  Test your mind with the first Java Challenger in a new series. Can you outthink the Java virtual machine?


What is the difference between Multiple Dispatch and Overloading , Method overriding is one of the ways in which Java supports Runtime Polymorphism. Dynamic method dispatch is the mechanism by which a call to an overridden  And Java does not support multiple dispatch. In statically typed languages, including Java, the biggest difference between dispatch and overloading is that overloading is based on the static type of parameters (i.e. the choice of which method is actually called is decided compile-time), while dispatch is based on the dynamic types (i.e. the decision is made runtime).


MultipleDispatch, Overridden methods are another way that Java implements the “one interface, multiple methods” aspect of polymorphism. Dynamic Method Dispatch is one of the most powerful mechanisms that object-oriented design brings to bear on code reuse and robustness.