2

Is there a language allowing a supertype A defining a method useFoo (Foo foo) such as B, derivated from A defining a method useFoo(Bar bar), (Bar is derivated from Foo), when using B as a A with a Foo that is a Bar, it will run the most specialised version of useFoo ?

Java example (not working, unfortunately) :

public class Foo {

}

public class Bar extends Foo {

}


public class A {
    void useFoo (Foo foo) {
        System.out.println("A");
    }
}

public class B extends A {
    void useFoo (Bar bar) {
        System.out.println("B");
    }
}

public static void main(String[] args) {
    A b = new B();
    b.useFoo(new Bar()); // actually returns "A", is there one returning "B" ?
}

I know there is a way to make this happen with a "few" lines (using a visitor for instance) but I would like to know if any (compiled) language would allow it.

I admit I would like to know if this is even possible, the contrary would not surprise me, and what prevents it ?

Is there a better name for this concept ?

Edit : In java, it is named Contravariance. thank you @Kevinrob

Pierre-Antoine Guillaume
  • 1,047
  • 1
  • 12
  • 28

1 Answers1

1

Your question is related to the following notions:

  1. Covariance: an argument may be redefined in subclasses to be a subclass of the original argument class. This convention is used in Eiffel, for example. The approach is known to lead to type safety issues, CAT-calls (CAT = Changing Availability or Type), that need to be addressed in a special way to preserve type system soundness. The strong argument for covarince is that it combines nicely with contracts (e.g., with Design by Contract).
  2. Multiple dispatch: method calls are performed by relying not only on type a target of a call, but also on types of arguments. The page lists several languages that support this mechanism. Multiple dispatch is a way to deal with covariance and contravariance. However one has to be careful when designing sets of methods that rely on the mechanism to avoid executing an unexpected method at run-time.
  3. Generic programming: instead of fixing argument types by the suppliers, they can be fixed by the clients. The mechanism is type safe and is free from the issues of the preceding two, but it requires actual generic parameters to be explicitly specified by the clients and if there are too many such arguments the type declarations may become unwieldy. Nowadays there are a lot of languages that support it.
Alexander Kogtenkov
  • 5,770
  • 1
  • 27
  • 35
  • I really see the point of #1 & #2, but why #3 ? In my opinion, if one can extend the functionnality without having to write code exponentially (let's say, a visitor which has to be detailed for each and every possible case), it's better. (though risky, seeing your #2). Do you think you can provide me with some more information ? Let me be clear, I use these techniques, i'm just curious. – Pierre-Antoine Guillaume Jun 08 '16 at 13:17
  • @PierreAntoineGuillaume, #3 is indeed a bit aside from the original question, I've added it based on my personal experience: when there is a need for code reuse, different argument and result types and type safety, this can be achieved by using generic types. For example, you could have declared `A ` with `void useFoo (T foo)` that can be safely redefined in `B `. Then you would write `A b = new B ();` and `b.useFoo(new Bar());` would print `"B"` as you wanted. – Alexander Kogtenkov Jun 08 '16 at 13:52
  • I don't think i will get a better answer, therefore I close this question, but I tend to think the way it could be handled indeed provides a little tweaking, depending on which language is being used : in c++, template specialisation would undoubtedly provide this kind of feature. Im stuck with with java atm. Oh well, thank you very much for your insight ! – Pierre-Antoine Guillaume Jun 08 '16 at 13:56