Method Overloading supports polymorphism because it is one way that Java implements one-interface, multiple methods paradigm.
To understand how, I consider the following. In languages that do not support method overloading,
each method must be given a unique name. However, frequently I will want to implement essentially
the same method for different types of data. Consider the absolute value function. In languages
that do not support overloading, there are usually 3 or more versions of this function, each with
a slightly different name. For instance in C, the function abs() returns the absolute value of an
integer, labs() returns the absolute value of an long integer, fabs() returns the absolute value
of an floating-point value. Since C does not support overloading, each function has to have its
own name, even though all 3 functions do essentially the same thing. This makes the situation
more complex, conceptually, than it actually is. Although the underlying concept of each function
is the same, I will have 3 names to remember. This situation doesn’t occur in Java, because each
absolute value method can use the same name. Indeed, Java’s standard class library includes an
absolute value method, called abs(). This method is overloaded by Java’s Math class to handle all
numeric types. Java determines which version of abs() to call based upon type of argument.
There is no rule stating that overload method must relate to one another. However from a
stylistic point of view, method overloading implies a relationship. Thus, while I can use the
same name to overload unrelated method, I think I should not. For example, I could have use the
name sqr to create methods that return the square of an integer and the square root of a floating
point value. But these 2 operations are fundamentally different. Applying method overloading in
this manner is defeating its original purpose.
So in practice, should I only overload closely related operations? And any other reason to use overloaded methods besides this?
As far as I can see, method overloading is typically used only for supplying sensible default arguments to a method, in order to simplify the API. It can have some advantages when you or other users may not need all the offered flexibility available on your program/library.
Another valid use is for the primitive data types in Java, as you pointed out yourself.
void doThis() {
doThis(true);
}
void doThis(boolean firstArg) {
doThis(firstArg, 1);
}
void doThis(int secondArg) {
doThis(true, secondArg);
}
// actual logic using several parameters
void doThis(boolean firstArg, int secondArg) {
if (firstArg) {
System.out.println(secondArg+1);
}
else {
System.out.println(secondArg-1);
}
}
Of course this is a nonsense example, but it becomes more apparent when, for example, your method requires a PrintStream. You can supply System.out as the default in an overloaded method, but your logic should be in a method where any PrintStream can be supplied. Using the same method name for radically different uses or outputs is a big no-no, it would most likely infuriate anyone working with your code (including Future You: http://xkcd.com/1421/ ).
Related
I see similar questions asked for C++ and C# but not for Java. Is there a way I can define concrete types along with generics in a class signature? Something like this:
import java.util.Optional;
class Foo<T, Optional<O>> {
}
Compiler describes this as invalid syntax.
You're mixing up the declaration of a type variable and the usage of one.
In class Foo<T> {}, as well as public static <T> void foo() {}, the <T> part is declaring the types. It's equivalent to the x in public class Foo { int x; } - you are saying that there is a type variable and it has the name T, you're not using it.
Hence, Optional<O> is obviously illegal there. Just like int a + b is gobbledygook.
You CAN put a bound on your typevar; just like Number a doesn't just declare an a but also limits it to be a reference to some instance of Number (or null), you can do the same when you declare types: class Foo<T extends Number> puts a bound on T, decreeing that it must necessarily be Number or some subtype thereof.
Thus, in theory, you could do something like:
class Foo<T, O extends Optional<?>> {}
except that makes no sense, there's no reason to ever write that code. What is your intent? That the second typevar is optional? That doesn't work in java, unfortunately. No such thing as optional typevars.
That it can be an Optional<T>? Just T is any type, including Optional, so that isn't needed.
That it must be an Optional<T>? That's 'optional abuse'. Optional isn't type-orthogonal and thus isn't that kind of flexible. You mustn't write code that way. Optionals can make sense as the return type of a method and shouldn't be used anywhere else; parameters should never be typed that way, fields should never be typed that way, and they definitely should never show up in generics. Any code that calls a method that returns an optional should immediately 'unwrap' it (e.g. by chaining an .orElse call).
The language spec doesn't enforce it, but the language gives you zero tools to deal with optional dichotomy. Essentially that means any API or code that works that way is going to lack abstractive powers to an incredible degree, and would feel exceedingly clunky as a result.
For example, it is impossible to write a method in java that accepts either List<String>, or List<Optional<String>>, but not e.g. List<Optional<Number>>, and can operate on the provided list regardless. Eventhough that is an operation that makes perfect sense: You can trivially have a method that for example only reads from the list (never calls .add or .addAll or whatnot on the list), and when it reads, does nullchecks (which would be pointless for a list that contains never-null strings, but it doesn't harm anything). Or, the method does invoke .add, but always adds non-null things. adding a guaranteed not null string is a legal move on a 'list of never null strings' and also a legal move on 'list of could-be-null string refs', and yet, java doesn't let you write this method: That's why you shouldn't treat optional as a type-in-flight; APIs cannot deal with the dichotomy.
And yet, you can't write this in java or just about any other language that supports Optional. That's just one example, there are many, they all point to the same thing: Optional? Only sensible as return values from methods, and must be unwrapped immediately; any other usage of them is harmful and silly: Leads to bugs and code that is hard to maintain, and isn't particularly flexible (is hard to adapt to changing requirements).
I would like to ask if it is possible in Java 8+ to declare a generic bound T so that it extends superclass/superinterface U (which could be Object, or Serializable) but breaks compilation if T extends L (which must extend U first).
I have found this problem using filter range objects: one of my developers invoked the wrong method and spent much time questioning on why it was giving inconsistent results. So I wanted to help her changing the method signature, someway, to early detect that she is using wrong code.
I will display my example case in a very simplified way. We are talking about tables and dynamic filters.
#Displays a text "[field name] is equal to [value]"
#Value (T) must be Oject
#Internally uses Object::toString
#Null shows blank string
public static String <T> localizeEq(Localizable fieldName, T value);
<LocalDate> localize(forI18nLabel("DATE_OF_BIRTH_LABEL",dateOfBirth)
"Date of birth equals 01/01/1900" (en)
"syntymäaika on 01/01/1990" (fi)
#Additional diplays for "ge, gte, le..."
#Overload methods not displayed
#SimpleFilter is {op:"ge|ge|eq...",value:""}}
#The effective display depends on the op attribute
#Example "[field name] is [operator] [value]"
#Example "[field name] is less or equal than [upper]"
#If <filter != null but filter.op == null || filter.value> the method returns null
public static String <T> localize(Localizable fieldName, SimpleFilter<T> filter)
#localize(forI18nLabel("SALARY"),salaryFilter)
#salaryFilter = {op:"lt",value:10000}
#Salary is less than 10000 (en)
Now the problem is that the the upper bound U of my generics is Serializable and developer inadvertently invoked localizeEq, which accepts atomic values, with a parameter of type SimpleFilter<?> that extends Serializable. The method localizeEq builds a filter text "[field name] is equal to {op:null,value:null}".
The main issue is the null check. Methods that operate on atomic values (e.g. localizeEq, localizeNe) check if the parameter is null. Methods that operate on complex filters check that either the filter parameter is null or its value is null before going on.
That is the reason of the question. Obviously I can (will amend my code in order to) inspect the type of the value parameter when the method is invoked but has three drawbacks:
Developers find it only at runtime
Developers find the problem only when value is not null
Nobody in my company runs automated tests, so they will find out only when kickstarting the entire application and setting a non-null value to the filter. Once a manual test is done, it is never repeated
[Edit]
For my specific case there is another trick, but it involves creating more than a dozen overloaded deprecated methods:
#Deprecated
public static String localize[Eq|Ne...](Localizable fieldName, SimpleFilter<?> value){ throw new UnsupportedOperationException("Wrong method");}
[Edit 3]
The code is on Gist. Please note that in repository code we statically import SimpleFilter.filter or LocalDateRangeFilter.filter methods. In the question it is assumed that localize(Localizable,SimpleFilter) is part of the same class than other methods. And please note there are a few other *RangeFilter classes to support Joda Time, Java Util Date and NumericRange in our repository. They all suffer same issue.
I would like to focus anyway on the scope of the question: forbidding extension in generic, which seems not possible in the JLS.
I would like to ask if it is possible in Java 8+ to declare a generic
bound T so that it extends superclass/superinterface U (which could be
Object, or Serializable) but breaks compilation if T extends L (which
must extend U first).
The T in your pseudocode seems to be a type parameter, not a bound. Bounds are something different, and in fact, putting a bound on T seems to be what you are asking about. Indeed, without one -- in particular, without a lower bound -- your localizeEq() method is not gaining anything from being generic. As it stands, that method would be clearer if you just got rid of T altogether, and declared the second parameter to be of type Object (which would be equivalent to the current code) or Serializable or whatever.
I take it that the method was made generic in hopes of somehow using its type parameter to exclude arguments of certain subtypes, but that is not possible in Java, because
lower type bounds are inclusive, not exclusive
lower type bounds limit types meeting the bound to a single line of inheritance, which seems inconsistent with your intent
Now the problem is that the the upper bound U of my generics is
Serializable and developer inadvertently invoked localizeEq, which
accepts atomic values, with a parameter of type SimpleFilter<?> that
extends Serializable. The method localizeEq builds a filter text
"[field name] is equal to {op:null,value:null}".
If one is not supposed to pass a SimpleFilter to the localizedEq() method then I'd say that you have a design flaw here. You could catch violations at runtime, of course, but the type system does not provide a way to express the compile-time constraint you're looking for.
For my specific case there is another trick, but it involves creating more than a dozen overloaded deprecated methods:
Indeed, overloading is probably the best available solution, but I would suggest approaching it from the other direction. Instead of adding overloads for localizeEq, localizeNe, etc., deprecate the existing versions of those methods and instead overload localize with a version or versions that provide the wanted behavior for arguments that are not SimpleFilters.
I have a code that looks like this
function a(Object m) {}
function a(BasicDbObject) {}
function a(TypeA) {}
function a(TypeB) {}
function a(TypeC) {}
.....
function b(Object m) {
// Some function using Java reflection to determine class of Object m
Class X = c(m);
a(X.cast(m));
}
Here is the problem. It always execute a(Object m) rather than a(BasicDbObject m), even it is BasicDbObject.
My end goal is to execute most closest function to the object passed.
What you are trying cannot be done, because Java is statically typed, and the method overload is resolved at compile-time, not run-time.
The only way to resolve the overload at runtime, is for the method call itself to be done with reflection.
Serious non-answer: wrong approach.
You don't use reflection to dynamically determine a type, to then figure which overloaded method to call.
Instead, use polymorphism. Meaning: don't overload, but override.
Rest assured: getting "reflection" working is hard. Getting it correct, and robust and stable is a super challenging, uphill battle.
You basically want to invent your own personal dynamic dispatch implementation. Unless you have super hard pressing reasons to do so, that is a terrible idea. Because chances are that you will get it wrong. Many many times. And even when your code is working, there will be many incidents later on, when unforeseen things happen in production.
As said: don't do this. Don't fight the language, instead use the means that the language offers you to solve such problems: an inheritance tree of classes, and polymorphic methods. Then let the JVM decide which method to invoke. Most likely, the JVM will do a much better job, compared to what you will come up with.
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.
This program compiles and runs in C++ but doesn't in a number of different languages, like Java and C#.
#include <iostream>
using namespace std;
void foo2() {
cout << "foo 2.\n";
}
void foo() {
return foo2();
}
int main() {
foo();
return 0;
}
In Java this gives a compiler error like 'Void methods cannot return a value'. But since the method being called is a void itself, it doesn't return a value. I understand that a construct like this is probably prohibited for the sake of readability. Are there any other objections?
Edit: For future reference, I found some a similar question here return-void-type-in-c-and-c
In my humble opinion this question isn't answered yet.
The reply 'Because it says so in the specification, move on' doesn't cut it, since someone had to write the specification in the first place. Maybe I should have asked 'What are the pros and cons of allowing returning a void type like C++'?
It's because of the possibility of its usage in templates. C# and Java forbid void as a type argument, but C++ permits it to allow you to write template code like this:
template<typename T, typename TResult>
TResult foo(T x, T y)
{
return foo2(x, y);
}
If void methods weren't allowed to return a void expression, this template instantiation would be impossible if TResult was void. If that were the case, you would need a separate template definition if you ever wanted TResult to actually be void.
For example, remember how in C# there are two sets of generic general-purpose delegates, namely Func<> and Action<>? Well, Action<T> exists precisely because Func<T, void> is forbidden. The C++ designers didn't want to introduce situations like this wherever possible, so they decided to allow you to use void as a template argument -- and the case you found is a feature to facilitate exactly that.
(Allow me to write the rest in a pretend-Q&A format.)
But why do C# and Java not allow a similar construct?
First, realize how generic programming is made possible in those languages:
C# and Java generics work by parsing a generic type (or method) definition and making sure it is valid for the generic constraints/bounds you have provided.
C++ templates are a search-and-replace mechanism with a powerful metaprogramming language around them. They are not required to make sense in the absence of specific template arguments -- they go from the "template metalanguage" to the "C++ language" (so to speak) only when they get their hands on actual arguments.
Why pick one approach of implementing generic programming over the other?
The generics approach maintains the nominal typing of the rest of the language. This has the advantage of allowing the (AOT) compiler to do static analysis, type checking, error reporting, overload resolution and eventually code generation once.
The templates approach is essentially duck typing. Duck typing in a nominally typed language doesn't have the advantages described above, but it allows you more flexibility in the sense that it will permit potentially "invalid" things ("invalid" from the point of view of a nominal type system) as long as you don't actually mention those invalid possibilities anywhere in your program. In other words, templates allow you to express a larger set of cases uniformly.
Okay, so what would C# and Java need to do to support void as a valid generic argument?
I would have to speculate to answer this, but I'll try.
At the language level, they would have to waive the notion that return; is valid only in void methods and always invalid for non-void methods. Without this change, very few useful methods could be instantiated -- and they would all probably have to end with recursion or an unconditional throw (which satisfies both void and non-void methods without returning). So to make this useful, C# and Java would also have to introduce the C++ feature of allowing you to return void expressions.
Okay, let's assume you have that and now you can write code like this:
void Foo2() { }
void Foo()
{
return Foo2();
}
Again, the non-generic version is as useless in C# and Java as it is in C++. But let's move on and see its real usefulness, which is in generics.
You should now be able to write generic code like this -- and TResult could now be void (in addition to all the other types that were already permitted):
TResult Foo<T, TResult>(T a)
{
return Foo2(a);
}
But remember that in C# and Java, overload resolution happens "early", rather than "late". The same callee will be chosen by the overload resolution algorithm for every possible TResult. And the type checker will have to complain, because you're either returning a void expression from a possibly non-void method or you're returning a non-void expression from a possibly void method.
In other words, the outer method can't be generic, unless:
The callee is also generic and its return type is defined by a generic type parameter that matches that of the outer method.
Overload resolution in generic types and methods is postponed until actual type arguments are made available, so that we can pick a correct non-generic method at the call spot.
What if we went with the first option - make the callee's return type generic and move on?
We could do that, but it simply pushes our problem to the callee.
At some point, we would need some way to "instantiate" some kind of void instance and optionally be able to receive it somehow. So now we would need constructors for void (although every void method could count as a factory method, if you squint) and we would also need variables of type void, possible conversions from void to object, and so on.
Basically, void would have to become a regular type (e.g. a regular empty struct) for all intents and purposes. The implications of this aren't terrible, but I think you can see why C# and Java avoided it.
What about the second option - postpone overload resolution?
Also entirely possible, but note that it would effectively turn generics into weaker templates. ("Weaker" in the sense that C++ templates aren't restricted to typenames.)
Again, it wouldn't be the end of the world, but it would involve losing the advantages of generics that I described earlier. The designers of C# and Java clearly want to keep those advantages.
Sidenote:
In C#, there is one special case I know of, where binding happens after the validation of the generic type definition. If you have a new() constraint on a T and you attempt to instantiate a new T(), the compiler will generate code that checks whether T is a value type or not. Then:
For value types, new T() becomes default(T) -- remember that C# default struct constructors aren't really constructors in the CLR sense.
For reference types, Activator.CreateInstance is called, which is an indirect constructor invocation using reflection.
This particular case is very special because, even though it has completely postponed method binding to the runtime, the compiler can still perform static analysis, type checking and code generation once. After all, the type of the expression new T() is always T and a call to something that has an empty formal parameter list can be trivially resolved and verified.
According to the Java Language Specification §14.17:
A return statement with no Expression must be contained in one of the following, or a compile-time error occurs:
A method that is declared, using the keyword void, not to return a value (§8.4.5)
...
A return statement with an Expression must be contained in one of the following, or a compile-time error occurs:
A method that is declared to return a value
...
So, by declaring that a method is void, you are saying that it returns no value, so you are limited to using a return; statement with no expression.
Public class John {
public void setValue(){
this.value = 0;
}
public void setValue(int v){
this.value = v;
}
Now potentially how would i call these two methods??
John j = new John();
j.setValueO();
j.setValue(10);
Correct me if i am wrong.
Is function overloading a concept of polymorphism? If not, under which OOP branch does this come.
Encapsulation means Hiding the information and Abstraction means Hiding the implantation details. So when i do overload a method, do i carry anything on these two above... {Abstraction and Encpsulation}
Is Overloading compile time or runtime? Why do they call this for overloading and overriding?
Yes you are right, expect the typo which you have made?
Is function overloading a concept of polymorphism? If not, under
which OOP branch does this come.
Well speaking from historical point of view, it does come but still many argue that its not a form of polymorphism.
Overloading
The method functions differently based on the arguements.
Overriding
The method functions differently based on which class was used to instainate it.The method bark could sound differently for Class CAT and Class DOG.
Encapsulation means Hiding the information and Abstraction means
Hiding the implantation details. So when i do overload a method, do i
carry anything on these two above... {Abstraction and Encpsulation}
Nope. May be someone can answer on this much clearer.
Is Overloading compile time or runtime? Why do they call this for
overloading and overriding?
Compile time. In overriding the decision that method of which class is to be called is decided at runtime, hence it is runtime.
In overloading the method definition, availability based on the parameters passed in the method call is checked at compile time only.
Java does not identify methods by their names alone, but by their signatures. A signature is composed of the method name and the ordered list of parameter types. So, from a compiler and jvm point of view, those are two completely different methods. The fact that they share the name (and as a consequence a similar signature) has no meaning if not for humans.
Since signatures are used in .class files, the compiler is responsible for computing the signature of a method call, using method name and parameters, at compile time. The late binding that happens at runtime is related to polymorphism, beacuse the current instance on which a certain method is called could be an instance of a subclass that override a certain method, wether that method is also overloaded or not, in java, is not considered by the runtime at all.
You cannot have two method with the same signature in the same class. Notably, the return type of a method is not part of its signature, so you cannot have two method with the same and and same parameters but returning two different types.
In other languages, javascript for example, since parameters are always dynamic, the signature is only composed of the name of the method, which makes overloading impossible
As to the first part of your question, yes the code you showed is an example of overloading, well, assuming the first part is correct and the 0 in the second part is a typo.
I'm not familiar with how these topics are formally taught these days, but to my mind overloading isn't really related to polymorphism. It's just a convenient way for methods that more or less do the same thing (and often call each other) to share a name. I have no idea how to answer your second question. What is an "OOP branch"?
Again, I'm not quite sure how these tie in. Doesn't it depend on what the method actually does?
Well, think about it this way. In Java, when you call a method in general, leaving overloading aside, at what phase does the system figure out which method you're calling (as opposed to which class's implementation of that method)? As to the origin of those terms, honestly that should be pretty easy to look up.
Since function overloading can work very well without objects, I do not see any reason for it to be an OOP concept at all. For the question whether it's polymorphism, it does fulfill the general requirements and according to Wikipedia is a form of polymorphism.
In general, when you create a method you always do both (you abstract away some general functionality and you hide the information of the internal workings of the function). Overloading does not add to neither, IMO. (Even though through overloading and the gained polymorphism you could argue to gain in abstraction, since the function becomes more generic, it is IMO still on the same level of abstraction.)
Overload resolution is - which was suprising to me at first - compile time. This is in contrast to the mentioned overriding. (So its in that sense not the same kind of polymorphism, as one is runtime and the other one is compile time.)