How does java compiler most specific method calling rule work?
Java will always try to use the most specific version of a method that is available.
The two methods
public void show(Object o) { ... }
public void show(String s) { ... }
could take null
as a valid value. In this scenario the overload taking a String
parameter is used, because String
is more specific than Object
.
If you add a third method
public void show(Integer t) { ... }
your code wouldn't compile any more because String
and Integer
are not related. Neither is more specific than the other and the compile is not able to decide which one to use.
Java Class.cast to most specific with method overloading
function a(Object m) {}
function a(BasicDbObject) {}
When methods are overloaded, it may not be intuitive to know the method which gets invoked for any set of parameters because, unlike the situation with overridden methods, the method overloading that gets invoked is determined at compile time (i.e. statically) rather than at run time (i.e. dynamically). This behavior is confusing because overriding methods is more common and this sets our expectations for method invocation.
There are some rules for doing method overloading as robustly and as simply as possible. These are all nicely enumerated in Effective Java (J. Bloch, 2nd and 3rd eds.).
Your situation is made complex because:
- You have two overloadings with the same number of parameters whose types are not radically different ... and ...
- The behavior of the overloadings is apparently dependent on the type of the parameter (if the behavior was identical, then you simply have one overloading forward to the other)
When this situation arises, you should try to correct it by giving the overloadings different names. It should always be possible to do this and doing so often improves the clarity and maintainability of the code.
If this can't be done for any reason, then the best workaround is to replace the overloadings with a method that accepts the most general parameter type and which invokes helper methods based on the most specific type of the passed argument.
So instead of the above, you can get the behavior you want by using...
public Function a(Object m) {
if (m instanceof BasicDbObject) return doDbObject(m);
if (m instanceof OtherDbObject) return doOtherDbObject(m);
return doGenericObject(m);
}
Note that this isn't the code that you would use when Java adopts pattern matching in the language. Note also that the effect of this code is to give your overloadings different names, but the selection of the distinct method is made at run time using instanceof
comparisons rather than at compile time by simply using a distinct name.
TLDR; if you are doing method overloading in a circumstance in which the parameter types are not (or may not be) radically different then you are better off not overloading and using distinct method names.
Method overloading and choosing the most specific type
Java uses early binding. The most specific method is chosen at compile time. The most specific method is chosen by number of parameters and type of parameters. Number of parameters is not relevant in this case. This leaves us with the type of parameters.
What type do the parameters have? Both parameters are expressions, using the ternary conditional operator. The question reduces to: What type does the conditional ternary operator return? The type is computed at compile time.
Given are the two expressions:
(10%2==0)? null : new Object(); // A
(10%2==0)? null : null; // B
The rules of type evaluation are listed here. In B
it is easy, both terms are exactly the same: null
will be returned (whatever type that may be) (JLS: "If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression."). In A
the second term is from a specific class. As this is more specific and null
can be substituted for an object of class Object
the type of the whole expression is Object
(JLS: "If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.").
After the type evaluation of the expressions the method selection is as expected.
The example with if
you give is different: You call the methods with objects of two different types. The ternary conditional operator always is evaluated to one type at compile time that fits both terms.
Is it possible to get c# to use method overload of most specific type rather than base type?
This code reminds me of the Haddocks' Eyes poem:
But I was thinking of a plan
To dye one's whiskers green,
And always use so large a fan
That they could not be seen.
First, your code creates a subclass, but then it casts the object back to the base class, so the compiler cannot see the actual type! The overload in your example is resolved at compile time, so the Compose(BaseClass item)
will be called.
You could turn things around and have .NET resolve the overload dynamically for you by hiding all overloads, and exposing a single method that takes a base class and performs a dynamic cast:
public class Processor {
public string Compose(BaseClass item) {
return ComposeImpl((dynamic)item);
}
private string ComposeImpl(BaseClass item) {
return item.Foo;
}
private string ComposeImpl(DerivedClass item) {
return ComposeImpl((BaseClass)item) + item.Bar;
}
}
The "magic" is on this line:
return ComposeImpl((dynamic)item);
the item
is cast to dynamic
, which tells the system that the actual overload of ComposeImpl
must be picked based on the run-time type of the BaseClass
object.
Related Topics
How to Handle Two Different Types in an Array in Swift for a Uitableview
Scenekit - Custom Geometry Does Not Show Up
Cannot Add Alamofire to Swift Project
How to Convert Hexstring to Bytearray in Swift 3
Find Multiple Quoted Words in a String with Regex
Multiple Enum Types List All Cases
Hide Password with "•••••••" in a Textfield
How to Display Image from a Url in Swiftui
Declaring and Using Custom Attributes in Swift
Disable Scrolling in Swiftui List/Form
Swift Realm Property '*' Has Been Added to Latest Object Model Migration
Realitykit as a Framework to Build 3D Nonar Apps
How Are Hash Collisions Handled