Passing an argument that could be of multiple types to a method in Java?
I am using a library with a method foo
with a signature like this:
TypeR foo(TypeA first, int second)
TypeR foo(TypeB first, int second)
TypeR foo(TypeC first, int second)
I am writing my own method bar
calling foo
, and I want to directly pass the first parameter along to foo
:
bar(??? first, int baz) {
int second = someCalculation(baz);
return foo(first, second);
}
My problem is that I do not know what type I should give to the parameter first
in bar
. There does not seem to be union typs in Java. How can I solve this without having to write three almost identical versions of bar
?
The types TypeA
to TypeC
do not share a common interface, and I have no control over them or foo
since they are in an external library. All I can control is how I implement bar
.
java methods types
add a comment |
I am using a library with a method foo
with a signature like this:
TypeR foo(TypeA first, int second)
TypeR foo(TypeB first, int second)
TypeR foo(TypeC first, int second)
I am writing my own method bar
calling foo
, and I want to directly pass the first parameter along to foo
:
bar(??? first, int baz) {
int second = someCalculation(baz);
return foo(first, second);
}
My problem is that I do not know what type I should give to the parameter first
in bar
. There does not seem to be union typs in Java. How can I solve this without having to write three almost identical versions of bar
?
The types TypeA
to TypeC
do not share a common interface, and I have no control over them or foo
since they are in an external library. All I can control is how I implement bar
.
java methods types
if TypeA, TypeB, and TypeC all extend a common base class or implement a common interface, then write your method in terms of 'that' type. Otherwise, you may be able to use a 'Generic Type'
– Tom Drake
Nov 20 at 19:56
add a comment |
I am using a library with a method foo
with a signature like this:
TypeR foo(TypeA first, int second)
TypeR foo(TypeB first, int second)
TypeR foo(TypeC first, int second)
I am writing my own method bar
calling foo
, and I want to directly pass the first parameter along to foo
:
bar(??? first, int baz) {
int second = someCalculation(baz);
return foo(first, second);
}
My problem is that I do not know what type I should give to the parameter first
in bar
. There does not seem to be union typs in Java. How can I solve this without having to write three almost identical versions of bar
?
The types TypeA
to TypeC
do not share a common interface, and I have no control over them or foo
since they are in an external library. All I can control is how I implement bar
.
java methods types
I am using a library with a method foo
with a signature like this:
TypeR foo(TypeA first, int second)
TypeR foo(TypeB first, int second)
TypeR foo(TypeC first, int second)
I am writing my own method bar
calling foo
, and I want to directly pass the first parameter along to foo
:
bar(??? first, int baz) {
int second = someCalculation(baz);
return foo(first, second);
}
My problem is that I do not know what type I should give to the parameter first
in bar
. There does not seem to be union typs in Java. How can I solve this without having to write three almost identical versions of bar
?
The types TypeA
to TypeC
do not share a common interface, and I have no control over them or foo
since they are in an external library. All I can control is how I implement bar
.
java methods types
java methods types
edited Nov 20 at 20:08
asked Nov 20 at 19:49
Anders
5,50463052
5,50463052
if TypeA, TypeB, and TypeC all extend a common base class or implement a common interface, then write your method in terms of 'that' type. Otherwise, you may be able to use a 'Generic Type'
– Tom Drake
Nov 20 at 19:56
add a comment |
if TypeA, TypeB, and TypeC all extend a common base class or implement a common interface, then write your method in terms of 'that' type. Otherwise, you may be able to use a 'Generic Type'
– Tom Drake
Nov 20 at 19:56
if TypeA, TypeB, and TypeC all extend a common base class or implement a common interface, then write your method in terms of 'that' type. Otherwise, you may be able to use a 'Generic Type'
– Tom Drake
Nov 20 at 19:56
if TypeA, TypeB, and TypeC all extend a common base class or implement a common interface, then write your method in terms of 'that' type. Otherwise, you may be able to use a 'Generic Type'
– Tom Drake
Nov 20 at 19:56
add a comment |
6 Answers
6
active
oldest
votes
The closest I can think of is something like this (removing the stuff relating to second
since it is irrelevant to the point).
TypeR bar(Object first) {
TypeR retvalue;
if (first instanceof TypeA)
retvalue = foo( (TypeA)first );
else if (first instanceof TypeB)
retvalue = foo( (TypeB)first );
else if (first instanceof TypeC)
retvalue = foo( (TypeC)first );
return retvalue;
}
If there is a more specific known supertype of TypeA etc., you could obviously use that instead of Object
as the parameter.
This is only possible if all three versions of foo
have the same return type.
Sadly, this "solution" is not really better, and maybe worse, than writing three overloaded versions of bar
.
it is not a good practice to useinstaceof
– elbraulio
Nov 20 at 20:03
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it withint
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.
– Dave Costa
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions offoo
share the same return type.
– Anders
Nov 20 at 20:09
@BraulioLopez I would be interested in references for why it's bad practice to useinstanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, usinginstanceof
seems perfectly reasonable.
– Mike
Nov 20 at 20:15
|
show 1 more comment
In theory, nothing prevents you from using typeclasses for ad-hoc polymorphism in Java:
interface Fooable<T> {
int foo(T t, int second);
}
public int bar<T>(T t, int baz, Fooable<T> fooable) {
int second = someCalculation(baz);
return fooable.foo(t, second);
}
The implementations would look roughly as follows:
public class TypeAFooable implements Fooable<TypeA> {
public int foo(TypeA t, int second) { return yourLibrary.foo(t, second); }
}
And invocations would look like
bar(myTypeAThing, 1234, new TypeAFooable());
If bar
were a little bit longer, this would bring several advantages:
- if
bar
makes lots of calls tofoo
in lots of different places, then you could define each instance of the typeclass once, instead of having multipleif-instanceof
-branches inside ofbar
- if you later want to make it work with
TypeD
,TypeE
, ...,TypeZ
, you don't have to dig into code ofbar
, you can simply supply yet another typeclass implementation - more importantly: if someone else wanted to use it with
TypeD
,TypeE
, etc., then they could supply yet another typeclass implementation, without having to fork yourbar
implementation.
In practice, the problem is that the typeclass instances won't be supplied automatically by the compiler, so it's usually not worth the hassle. Unless bar
is somehow gigantic and super-complex, just overload it, or use instanceof
.
add a comment |
You can define first as a generic type type in bar as below.
bar(Object first, int baz) {
int second = someCalculation(baz);
if(first instanceOf TypeA) return foo((TypeA) first, second);
else if(first instanceOf TypeB) return foo((TypeB) first, second);
else if(first instanceOf TypeC) return foo((TypeC) first, second);
else throw new CustomException("Object pass in is not of correct type");
}
add a comment |
I would attempt to avoid this problem by decomposing your bar()
function into the piece that deals with computing int second
and the piece that deals with TypeA
/B
/C first
. That way you could write something like
int second = decomposedPortion(baz);
TypeR result = foo(first, second);
add a comment |
We can replace the call of foo
in bar
by a call of a corresponding BiFunction
. Thus for all overloaded foo
methods a BiFunction
has to be defined.
private static final Map<Class<?>, BiFunction<?, Integer, TypeR>> FOO = Map.of(
TypeA.class, (first, second) -> foo((TypeA) first, second),
TypeB.class, (first, second) -> foo((TypeB) first, second),
TypeC.class, (first, second) -> foo((TypeC) first, second));
But for every overloaded foo
mapping one line only has to be written whereas each overloaded bar
method would need four lines if it were written as like in the question.
Now we can make bar
generic. But the following will not work, since the returned BiFunction
has an unbound wildcard as first type parameter.
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return FOO.get(first.getClass()).apply(first, second);
}
We would need to declare FOO
as Map<Class<T>, BiFunction<T, Integer, TypeR>>
but that's not possible. To work around this we define a method with a type parameter T
which is supposed to establish the missing type equality. But that's not for free. It's at the cost of a warning resulting from casting:
private static <T> BiFunction<T, Integer, TypeR> fooOf(Object o) {
return (BiFunction<T, Integer, TypeR>) FOO.get(o.getClass());
}
Now we can use this method in bar
:
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return fooOf(first).apply(first, second);
}
This is similar to an instanceof
approach but displaces the type distinction from the method bar
to the Map
FOO
. If there are other methods than bar
which also need to call foo
in a similar way, the type distinction has not be coded again. FOO
and fooOf
can be reused. If the library changes and an additional overloaded TypeR foo(TypeD first, int second)
gets introduced, only FOO
needs to be updated by adding one additional line.
This approach requires first
to be not null
.
add a comment |
Use interfaces like this:
interface Type { //...}
class TypeA implements Type { //...}
class TypeB implements Type { //...}
class TypeC implements Type { //...}
then you will only need one foo function
foo(Type first, int second)
and one bar function
bar(Type first, int baz)
1
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that thefoo()
methods are in a library.
– Dave Costa
Nov 20 at 19:57
They do not implement a common interface, and I have no controls overtypeA
totypeC
orfoo
.
– Anders
Nov 20 at 19:57
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
I don't understand your question?
– Anders
Nov 20 at 20:07
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400523%2fpassing-an-argument-that-could-be-of-multiple-types-to-a-method-in-java%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
The closest I can think of is something like this (removing the stuff relating to second
since it is irrelevant to the point).
TypeR bar(Object first) {
TypeR retvalue;
if (first instanceof TypeA)
retvalue = foo( (TypeA)first );
else if (first instanceof TypeB)
retvalue = foo( (TypeB)first );
else if (first instanceof TypeC)
retvalue = foo( (TypeC)first );
return retvalue;
}
If there is a more specific known supertype of TypeA etc., you could obviously use that instead of Object
as the parameter.
This is only possible if all three versions of foo
have the same return type.
Sadly, this "solution" is not really better, and maybe worse, than writing three overloaded versions of bar
.
it is not a good practice to useinstaceof
– elbraulio
Nov 20 at 20:03
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it withint
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.
– Dave Costa
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions offoo
share the same return type.
– Anders
Nov 20 at 20:09
@BraulioLopez I would be interested in references for why it's bad practice to useinstanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, usinginstanceof
seems perfectly reasonable.
– Mike
Nov 20 at 20:15
|
show 1 more comment
The closest I can think of is something like this (removing the stuff relating to second
since it is irrelevant to the point).
TypeR bar(Object first) {
TypeR retvalue;
if (first instanceof TypeA)
retvalue = foo( (TypeA)first );
else if (first instanceof TypeB)
retvalue = foo( (TypeB)first );
else if (first instanceof TypeC)
retvalue = foo( (TypeC)first );
return retvalue;
}
If there is a more specific known supertype of TypeA etc., you could obviously use that instead of Object
as the parameter.
This is only possible if all three versions of foo
have the same return type.
Sadly, this "solution" is not really better, and maybe worse, than writing three overloaded versions of bar
.
it is not a good practice to useinstaceof
– elbraulio
Nov 20 at 20:03
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it withint
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.
– Dave Costa
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions offoo
share the same return type.
– Anders
Nov 20 at 20:09
@BraulioLopez I would be interested in references for why it's bad practice to useinstanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, usinginstanceof
seems perfectly reasonable.
– Mike
Nov 20 at 20:15
|
show 1 more comment
The closest I can think of is something like this (removing the stuff relating to second
since it is irrelevant to the point).
TypeR bar(Object first) {
TypeR retvalue;
if (first instanceof TypeA)
retvalue = foo( (TypeA)first );
else if (first instanceof TypeB)
retvalue = foo( (TypeB)first );
else if (first instanceof TypeC)
retvalue = foo( (TypeC)first );
return retvalue;
}
If there is a more specific known supertype of TypeA etc., you could obviously use that instead of Object
as the parameter.
This is only possible if all three versions of foo
have the same return type.
Sadly, this "solution" is not really better, and maybe worse, than writing three overloaded versions of bar
.
The closest I can think of is something like this (removing the stuff relating to second
since it is irrelevant to the point).
TypeR bar(Object first) {
TypeR retvalue;
if (first instanceof TypeA)
retvalue = foo( (TypeA)first );
else if (first instanceof TypeB)
retvalue = foo( (TypeB)first );
else if (first instanceof TypeC)
retvalue = foo( (TypeC)first );
return retvalue;
}
If there is a more specific known supertype of TypeA etc., you could obviously use that instead of Object
as the parameter.
This is only possible if all three versions of foo
have the same return type.
Sadly, this "solution" is not really better, and maybe worse, than writing three overloaded versions of bar
.
edited Nov 20 at 20:11
Anders
5,50463052
5,50463052
answered Nov 20 at 20:02
Dave Costa
38.6k54664
38.6k54664
it is not a good practice to useinstaceof
– elbraulio
Nov 20 at 20:03
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it withint
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.
– Dave Costa
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions offoo
share the same return type.
– Anders
Nov 20 at 20:09
@BraulioLopez I would be interested in references for why it's bad practice to useinstanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, usinginstanceof
seems perfectly reasonable.
– Mike
Nov 20 at 20:15
|
show 1 more comment
it is not a good practice to useinstaceof
– elbraulio
Nov 20 at 20:03
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it withint
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.
– Dave Costa
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions offoo
share the same return type.
– Anders
Nov 20 at 20:09
@BraulioLopez I would be interested in references for why it's bad practice to useinstanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, usinginstanceof
seems perfectly reasonable.
– Mike
Nov 20 at 20:15
it is not a good practice to use
instaceof
– elbraulio
Nov 20 at 20:03
it is not a good practice to use
instaceof
– elbraulio
Nov 20 at 20:03
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
I'm not particularly interested in blanket statements of what is "good practice". If you really think so, perhaps you could explain why. In any case, I simply posted the only technique I can think of that approaches what the poster is requesting.
– Dave Costa
Nov 20 at 20:08
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it with
int
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.– Dave Costa
Nov 20 at 20:09
@SotiriosDelimanolis maybe I'm misunderstanding your comment, but I think I possibly didn't explain. Since the OP didn't specify the return type of the functions, I just used T as a placeholder in my sample code. In reality I would replace it with
int
or whatever is the appropriate return type. I didn't mean to imply that the compiler would figure out the return type on its own.– Dave Costa
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions of
foo
share the same return type.– Anders
Nov 20 at 20:09
+1 for both pointing to a solution, and highlighting that overloading might be better. I updated the question to clarify that all versions of
foo
share the same return type.– Anders
Nov 20 at 20:09
@BraulioLopez I would be interested in references for why it's bad practice to use
instanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, using instanceof
seems perfectly reasonable.– Mike
Nov 20 at 20:15
@BraulioLopez I would be interested in references for why it's bad practice to use
instanceof
. In the case of working with 3rd party APIs in which you have no control over the class hierarchy, and which were possibly written prior to the advent of generics in Java, using instanceof
seems perfectly reasonable.– Mike
Nov 20 at 20:15
|
show 1 more comment
In theory, nothing prevents you from using typeclasses for ad-hoc polymorphism in Java:
interface Fooable<T> {
int foo(T t, int second);
}
public int bar<T>(T t, int baz, Fooable<T> fooable) {
int second = someCalculation(baz);
return fooable.foo(t, second);
}
The implementations would look roughly as follows:
public class TypeAFooable implements Fooable<TypeA> {
public int foo(TypeA t, int second) { return yourLibrary.foo(t, second); }
}
And invocations would look like
bar(myTypeAThing, 1234, new TypeAFooable());
If bar
were a little bit longer, this would bring several advantages:
- if
bar
makes lots of calls tofoo
in lots of different places, then you could define each instance of the typeclass once, instead of having multipleif-instanceof
-branches inside ofbar
- if you later want to make it work with
TypeD
,TypeE
, ...,TypeZ
, you don't have to dig into code ofbar
, you can simply supply yet another typeclass implementation - more importantly: if someone else wanted to use it with
TypeD
,TypeE
, etc., then they could supply yet another typeclass implementation, without having to fork yourbar
implementation.
In practice, the problem is that the typeclass instances won't be supplied automatically by the compiler, so it's usually not worth the hassle. Unless bar
is somehow gigantic and super-complex, just overload it, or use instanceof
.
add a comment |
In theory, nothing prevents you from using typeclasses for ad-hoc polymorphism in Java:
interface Fooable<T> {
int foo(T t, int second);
}
public int bar<T>(T t, int baz, Fooable<T> fooable) {
int second = someCalculation(baz);
return fooable.foo(t, second);
}
The implementations would look roughly as follows:
public class TypeAFooable implements Fooable<TypeA> {
public int foo(TypeA t, int second) { return yourLibrary.foo(t, second); }
}
And invocations would look like
bar(myTypeAThing, 1234, new TypeAFooable());
If bar
were a little bit longer, this would bring several advantages:
- if
bar
makes lots of calls tofoo
in lots of different places, then you could define each instance of the typeclass once, instead of having multipleif-instanceof
-branches inside ofbar
- if you later want to make it work with
TypeD
,TypeE
, ...,TypeZ
, you don't have to dig into code ofbar
, you can simply supply yet another typeclass implementation - more importantly: if someone else wanted to use it with
TypeD
,TypeE
, etc., then they could supply yet another typeclass implementation, without having to fork yourbar
implementation.
In practice, the problem is that the typeclass instances won't be supplied automatically by the compiler, so it's usually not worth the hassle. Unless bar
is somehow gigantic and super-complex, just overload it, or use instanceof
.
add a comment |
In theory, nothing prevents you from using typeclasses for ad-hoc polymorphism in Java:
interface Fooable<T> {
int foo(T t, int second);
}
public int bar<T>(T t, int baz, Fooable<T> fooable) {
int second = someCalculation(baz);
return fooable.foo(t, second);
}
The implementations would look roughly as follows:
public class TypeAFooable implements Fooable<TypeA> {
public int foo(TypeA t, int second) { return yourLibrary.foo(t, second); }
}
And invocations would look like
bar(myTypeAThing, 1234, new TypeAFooable());
If bar
were a little bit longer, this would bring several advantages:
- if
bar
makes lots of calls tofoo
in lots of different places, then you could define each instance of the typeclass once, instead of having multipleif-instanceof
-branches inside ofbar
- if you later want to make it work with
TypeD
,TypeE
, ...,TypeZ
, you don't have to dig into code ofbar
, you can simply supply yet another typeclass implementation - more importantly: if someone else wanted to use it with
TypeD
,TypeE
, etc., then they could supply yet another typeclass implementation, without having to fork yourbar
implementation.
In practice, the problem is that the typeclass instances won't be supplied automatically by the compiler, so it's usually not worth the hassle. Unless bar
is somehow gigantic and super-complex, just overload it, or use instanceof
.
In theory, nothing prevents you from using typeclasses for ad-hoc polymorphism in Java:
interface Fooable<T> {
int foo(T t, int second);
}
public int bar<T>(T t, int baz, Fooable<T> fooable) {
int second = someCalculation(baz);
return fooable.foo(t, second);
}
The implementations would look roughly as follows:
public class TypeAFooable implements Fooable<TypeA> {
public int foo(TypeA t, int second) { return yourLibrary.foo(t, second); }
}
And invocations would look like
bar(myTypeAThing, 1234, new TypeAFooable());
If bar
were a little bit longer, this would bring several advantages:
- if
bar
makes lots of calls tofoo
in lots of different places, then you could define each instance of the typeclass once, instead of having multipleif-instanceof
-branches inside ofbar
- if you later want to make it work with
TypeD
,TypeE
, ...,TypeZ
, you don't have to dig into code ofbar
, you can simply supply yet another typeclass implementation - more importantly: if someone else wanted to use it with
TypeD
,TypeE
, etc., then they could supply yet another typeclass implementation, without having to fork yourbar
implementation.
In practice, the problem is that the typeclass instances won't be supplied automatically by the compiler, so it's usually not worth the hassle. Unless bar
is somehow gigantic and super-complex, just overload it, or use instanceof
.
edited Nov 20 at 20:33
answered Nov 20 at 20:14
Andrey Tyukin
26.3k42347
26.3k42347
add a comment |
add a comment |
You can define first as a generic type type in bar as below.
bar(Object first, int baz) {
int second = someCalculation(baz);
if(first instanceOf TypeA) return foo((TypeA) first, second);
else if(first instanceOf TypeB) return foo((TypeB) first, second);
else if(first instanceOf TypeC) return foo((TypeC) first, second);
else throw new CustomException("Object pass in is not of correct type");
}
add a comment |
You can define first as a generic type type in bar as below.
bar(Object first, int baz) {
int second = someCalculation(baz);
if(first instanceOf TypeA) return foo((TypeA) first, second);
else if(first instanceOf TypeB) return foo((TypeB) first, second);
else if(first instanceOf TypeC) return foo((TypeC) first, second);
else throw new CustomException("Object pass in is not of correct type");
}
add a comment |
You can define first as a generic type type in bar as below.
bar(Object first, int baz) {
int second = someCalculation(baz);
if(first instanceOf TypeA) return foo((TypeA) first, second);
else if(first instanceOf TypeB) return foo((TypeB) first, second);
else if(first instanceOf TypeC) return foo((TypeC) first, second);
else throw new CustomException("Object pass in is not of correct type");
}
You can define first as a generic type type in bar as below.
bar(Object first, int baz) {
int second = someCalculation(baz);
if(first instanceOf TypeA) return foo((TypeA) first, second);
else if(first instanceOf TypeB) return foo((TypeB) first, second);
else if(first instanceOf TypeC) return foo((TypeC) first, second);
else throw new CustomException("Object pass in is not of correct type");
}
edited Nov 20 at 20:04
answered Nov 20 at 20:01
Rishab Ghanti
312
312
add a comment |
add a comment |
I would attempt to avoid this problem by decomposing your bar()
function into the piece that deals with computing int second
and the piece that deals with TypeA
/B
/C first
. That way you could write something like
int second = decomposedPortion(baz);
TypeR result = foo(first, second);
add a comment |
I would attempt to avoid this problem by decomposing your bar()
function into the piece that deals with computing int second
and the piece that deals with TypeA
/B
/C first
. That way you could write something like
int second = decomposedPortion(baz);
TypeR result = foo(first, second);
add a comment |
I would attempt to avoid this problem by decomposing your bar()
function into the piece that deals with computing int second
and the piece that deals with TypeA
/B
/C first
. That way you could write something like
int second = decomposedPortion(baz);
TypeR result = foo(first, second);
I would attempt to avoid this problem by decomposing your bar()
function into the piece that deals with computing int second
and the piece that deals with TypeA
/B
/C first
. That way you could write something like
int second = decomposedPortion(baz);
TypeR result = foo(first, second);
answered Nov 20 at 20:16
Ben P.
22.3k31846
22.3k31846
add a comment |
add a comment |
We can replace the call of foo
in bar
by a call of a corresponding BiFunction
. Thus for all overloaded foo
methods a BiFunction
has to be defined.
private static final Map<Class<?>, BiFunction<?, Integer, TypeR>> FOO = Map.of(
TypeA.class, (first, second) -> foo((TypeA) first, second),
TypeB.class, (first, second) -> foo((TypeB) first, second),
TypeC.class, (first, second) -> foo((TypeC) first, second));
But for every overloaded foo
mapping one line only has to be written whereas each overloaded bar
method would need four lines if it were written as like in the question.
Now we can make bar
generic. But the following will not work, since the returned BiFunction
has an unbound wildcard as first type parameter.
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return FOO.get(first.getClass()).apply(first, second);
}
We would need to declare FOO
as Map<Class<T>, BiFunction<T, Integer, TypeR>>
but that's not possible. To work around this we define a method with a type parameter T
which is supposed to establish the missing type equality. But that's not for free. It's at the cost of a warning resulting from casting:
private static <T> BiFunction<T, Integer, TypeR> fooOf(Object o) {
return (BiFunction<T, Integer, TypeR>) FOO.get(o.getClass());
}
Now we can use this method in bar
:
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return fooOf(first).apply(first, second);
}
This is similar to an instanceof
approach but displaces the type distinction from the method bar
to the Map
FOO
. If there are other methods than bar
which also need to call foo
in a similar way, the type distinction has not be coded again. FOO
and fooOf
can be reused. If the library changes and an additional overloaded TypeR foo(TypeD first, int second)
gets introduced, only FOO
needs to be updated by adding one additional line.
This approach requires first
to be not null
.
add a comment |
We can replace the call of foo
in bar
by a call of a corresponding BiFunction
. Thus for all overloaded foo
methods a BiFunction
has to be defined.
private static final Map<Class<?>, BiFunction<?, Integer, TypeR>> FOO = Map.of(
TypeA.class, (first, second) -> foo((TypeA) first, second),
TypeB.class, (first, second) -> foo((TypeB) first, second),
TypeC.class, (first, second) -> foo((TypeC) first, second));
But for every overloaded foo
mapping one line only has to be written whereas each overloaded bar
method would need four lines if it were written as like in the question.
Now we can make bar
generic. But the following will not work, since the returned BiFunction
has an unbound wildcard as first type parameter.
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return FOO.get(first.getClass()).apply(first, second);
}
We would need to declare FOO
as Map<Class<T>, BiFunction<T, Integer, TypeR>>
but that's not possible. To work around this we define a method with a type parameter T
which is supposed to establish the missing type equality. But that's not for free. It's at the cost of a warning resulting from casting:
private static <T> BiFunction<T, Integer, TypeR> fooOf(Object o) {
return (BiFunction<T, Integer, TypeR>) FOO.get(o.getClass());
}
Now we can use this method in bar
:
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return fooOf(first).apply(first, second);
}
This is similar to an instanceof
approach but displaces the type distinction from the method bar
to the Map
FOO
. If there are other methods than bar
which also need to call foo
in a similar way, the type distinction has not be coded again. FOO
and fooOf
can be reused. If the library changes and an additional overloaded TypeR foo(TypeD first, int second)
gets introduced, only FOO
needs to be updated by adding one additional line.
This approach requires first
to be not null
.
add a comment |
We can replace the call of foo
in bar
by a call of a corresponding BiFunction
. Thus for all overloaded foo
methods a BiFunction
has to be defined.
private static final Map<Class<?>, BiFunction<?, Integer, TypeR>> FOO = Map.of(
TypeA.class, (first, second) -> foo((TypeA) first, second),
TypeB.class, (first, second) -> foo((TypeB) first, second),
TypeC.class, (first, second) -> foo((TypeC) first, second));
But for every overloaded foo
mapping one line only has to be written whereas each overloaded bar
method would need four lines if it were written as like in the question.
Now we can make bar
generic. But the following will not work, since the returned BiFunction
has an unbound wildcard as first type parameter.
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return FOO.get(first.getClass()).apply(first, second);
}
We would need to declare FOO
as Map<Class<T>, BiFunction<T, Integer, TypeR>>
but that's not possible. To work around this we define a method with a type parameter T
which is supposed to establish the missing type equality. But that's not for free. It's at the cost of a warning resulting from casting:
private static <T> BiFunction<T, Integer, TypeR> fooOf(Object o) {
return (BiFunction<T, Integer, TypeR>) FOO.get(o.getClass());
}
Now we can use this method in bar
:
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return fooOf(first).apply(first, second);
}
This is similar to an instanceof
approach but displaces the type distinction from the method bar
to the Map
FOO
. If there are other methods than bar
which also need to call foo
in a similar way, the type distinction has not be coded again. FOO
and fooOf
can be reused. If the library changes and an additional overloaded TypeR foo(TypeD first, int second)
gets introduced, only FOO
needs to be updated by adding one additional line.
This approach requires first
to be not null
.
We can replace the call of foo
in bar
by a call of a corresponding BiFunction
. Thus for all overloaded foo
methods a BiFunction
has to be defined.
private static final Map<Class<?>, BiFunction<?, Integer, TypeR>> FOO = Map.of(
TypeA.class, (first, second) -> foo((TypeA) first, second),
TypeB.class, (first, second) -> foo((TypeB) first, second),
TypeC.class, (first, second) -> foo((TypeC) first, second));
But for every overloaded foo
mapping one line only has to be written whereas each overloaded bar
method would need four lines if it were written as like in the question.
Now we can make bar
generic. But the following will not work, since the returned BiFunction
has an unbound wildcard as first type parameter.
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return FOO.get(first.getClass()).apply(first, second);
}
We would need to declare FOO
as Map<Class<T>, BiFunction<T, Integer, TypeR>>
but that's not possible. To work around this we define a method with a type parameter T
which is supposed to establish the missing type equality. But that's not for free. It's at the cost of a warning resulting from casting:
private static <T> BiFunction<T, Integer, TypeR> fooOf(Object o) {
return (BiFunction<T, Integer, TypeR>) FOO.get(o.getClass());
}
Now we can use this method in bar
:
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return fooOf(first).apply(first, second);
}
This is similar to an instanceof
approach but displaces the type distinction from the method bar
to the Map
FOO
. If there are other methods than bar
which also need to call foo
in a similar way, the type distinction has not be coded again. FOO
and fooOf
can be reused. If the library changes and an additional overloaded TypeR foo(TypeD first, int second)
gets introduced, only FOO
needs to be updated by adding one additional line.
This approach requires first
to be not null
.
edited Nov 20 at 22:48
answered Nov 20 at 22:22
LuCio
2,7391823
2,7391823
add a comment |
add a comment |
Use interfaces like this:
interface Type { //...}
class TypeA implements Type { //...}
class TypeB implements Type { //...}
class TypeC implements Type { //...}
then you will only need one foo function
foo(Type first, int second)
and one bar function
bar(Type first, int baz)
1
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that thefoo()
methods are in a library.
– Dave Costa
Nov 20 at 19:57
They do not implement a common interface, and I have no controls overtypeA
totypeC
orfoo
.
– Anders
Nov 20 at 19:57
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
I don't understand your question?
– Anders
Nov 20 at 20:07
add a comment |
Use interfaces like this:
interface Type { //...}
class TypeA implements Type { //...}
class TypeB implements Type { //...}
class TypeC implements Type { //...}
then you will only need one foo function
foo(Type first, int second)
and one bar function
bar(Type first, int baz)
1
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that thefoo()
methods are in a library.
– Dave Costa
Nov 20 at 19:57
They do not implement a common interface, and I have no controls overtypeA
totypeC
orfoo
.
– Anders
Nov 20 at 19:57
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
I don't understand your question?
– Anders
Nov 20 at 20:07
add a comment |
Use interfaces like this:
interface Type { //...}
class TypeA implements Type { //...}
class TypeB implements Type { //...}
class TypeC implements Type { //...}
then you will only need one foo function
foo(Type first, int second)
and one bar function
bar(Type first, int baz)
Use interfaces like this:
interface Type { //...}
class TypeA implements Type { //...}
class TypeB implements Type { //...}
class TypeC implements Type { //...}
then you will only need one foo function
foo(Type first, int second)
and one bar function
bar(Type first, int baz)
answered Nov 20 at 19:55
elbraulio
4589
4589
1
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that thefoo()
methods are in a library.
– Dave Costa
Nov 20 at 19:57
They do not implement a common interface, and I have no controls overtypeA
totypeC
orfoo
.
– Anders
Nov 20 at 19:57
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
I don't understand your question?
– Anders
Nov 20 at 20:07
add a comment |
1
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that thefoo()
methods are in a library.
– Dave Costa
Nov 20 at 19:57
They do not implement a common interface, and I have no controls overtypeA
totypeC
orfoo
.
– Anders
Nov 20 at 19:57
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
I don't understand your question?
– Anders
Nov 20 at 20:07
1
1
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that the
foo()
methods are in a library.– Dave Costa
Nov 20 at 19:57
Yes, this would be a good design approach if the poster had the option. Unfortunately, the question states that the
foo()
methods are in a library.– Dave Costa
Nov 20 at 19:57
They do not implement a common interface, and I have no controls over
typeA
to typeC
or foo
.– Anders
Nov 20 at 19:57
They do not implement a common interface, and I have no controls over
typeA
to typeC
or foo
.– Anders
Nov 20 at 19:57
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
how do you decide wich type must be used to call foo?
– elbraulio
Nov 20 at 20:00
I don't understand your question?
– Anders
Nov 20 at 20:07
I don't understand your question?
– Anders
Nov 20 at 20:07
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400523%2fpassing-an-argument-that-could-be-of-multiple-types-to-a-method-in-java%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
if TypeA, TypeB, and TypeC all extend a common base class or implement a common interface, then write your method in terms of 'that' type. Otherwise, you may be able to use a 'Generic Type'
– Tom Drake
Nov 20 at 19:56