Is there an elegant way to obtain multiple dispatch for methods with 2 parameters (or even more) in OO languages with (single) dynamic dispatch?
Example of a possible problem:
This is a Java-inspired example. (the problem is not language related!)
// Visitable elements
abstract class Operand {
}
class Integer extends Operand {
int value;
public int getValue() {
return value;
}
}
class Matrix extends Operand {
int[][] value;
public int[][] getValue() {
return value;
}
}
// Visitors
abstract class Operator {
// Binary operator
public Operand eval(Operand a, Operand b) {
return null; // unknown operation
}
}
class Addition extends Operator {
public Operand eval(Integer a, Integer b) {
return new Integer(a.getValue() + b.getValue());
}
}
class Multiplication extends Operator {
public Operand eval(Integer a, Integer b) {
return new Integer(a.getValue() * b.getValue());
}
// you can multiply an integer with a matrix
public Operand eval(Integer a, Matrix b) {
return new Matrix();
}
}
I have many Operator and Operand concrete types but only refer to them through their abstract types:
Operand a = new Integer()
Operand b = new Matrix();
Operand result;
Operator mul = new Multiplication();
result = mul.eval(a, b); // Here I want Multiplication::eval(Integer, Matrix) to be called
I decided to add to this since the above two answers are somewhat incomplete. I was myself curious about this issue but couldn't find an answer so had to do my own analysis. In general there are two approaches that can be used to implement multi-methods in languages like C++ or Java that support both single dynamic dispatch and something like typeof or runtime type identification.
For the double dispatch case the visitor pattern is most common (for Arg1->foo(Arg2) ) and I gather in most cases is preferred to using RTTI and switches or if statements. One can also generalize the visitor approach to the n case by i.e. Arg1->foo(Arg2,Arg3..ArgN) by chaining a series of single dispatches that call methods in a treelike structure that differentiate on the type of the arguments up to some k and split the number of ways of the k+1 argument. For example for a simple case of triple dispatch and only two instances of each type:
interface T1 {
public void f(T2 arg2, T3 arg3);
}
interface T2 {
public void gA(A a, T3 arg3)
public void gB(B b, T3 arg3)
}
interface T3 {
public void hAC(A a,C c);
public void hAD(A a,D d);
public void hBC(B b,C c);
public void hBD(B b,D d);
}
class A implements T1 {
public void f(T2 arg2, T3 arg3) {
arg2->gA(this,arg3);
}
}
class B implements T1 {
public void f(T2 arg2, T3 arg3) {
arg2->gB(this,arg3);
}
}
class C implements T2 {
public void gA(A a,T arg3) {
arg3->hAC(a, this);
}
public void gB(B b,T arg3) {
arg3->hBC(b, this);
}
}
class D implements T2 {
public void gA(A a,T arg3) {
arg3->hAD(a, this);
}
public void gB(B b,T arg3) {
arg3->hBD(b, this);
}
}
class E implements T3 {
public void hAC(A a,C c) {
System.out.println("ACE");
}
public void hAD(A a,D d) {
System.out.println("ADE");
}
public void hBC(B b,C c) {
System.out.println("BCE");
}
public void hBD(B b,D d) {
System.out.println("BDE");
}
}
class F implements T3 {
public void hAC(A a,C c) {
System.out.println("ACF");
}
public void hAD(A a,D d) {
System.out.println("ADF");
}
public void hBC(B b,C c) {
System.out.println("BCF");
}
public void hBD(B b,D d) {
System.out.println("BDF");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
C c = new C();
E e = new E();
a.f(c,e);
}
}
Though the approach generalizes the problem are quite obvious. For each endpoint function in the worse case one has to write n-1 dispatch functions.
One can achieve something similar with runtime type identification via the instanceOf operator:
class Functions
{
static void f(A a,C c,E e) {
System.out.println("ACE");
}
static void f(A a,C c,F f) {
System.out.println("ACF");
}
static void f(A a,D d,E e) {
System.out.println("ADE");
}
static void f(A a,D d,F f) {
System.out.println("ADF");
}
static void f(B b,C c,E e) {
System.out.println("BCE");
}
static void f(B b,C c,F f) {
System.out.println("BCF");
}
static void f(B b,D d,E e) {
System.out.println("BDE");
}
static void F(B b,D d,F f) {
System.out.println("BDF");
}
static void dispatch(T1 t1, T2 t2, T3 t3) {
if( t1 instanceOf A)
{
if(t2 instance of C) {
if(t3 instance of E) {
Function.F( (A)t1, (C)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (A)t1, (C)t2, (F)t3 );
}
}
else if(t2 instance of D) {
if(t3 instance of E) {
Function.F( (A)t1, (D)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (A)t1, (D)t2, (F)t3 );
}
}
}
else if(t1 instanceOf B) {
if(t2 instance of C) {
if(t3 instance of E) {
Function.F( (B)t1, (C)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (B)t1, (C)t2, (F)t3 );
}
}
else if(t2 instance of D) {
if(t3 instance of E) {
Function.F( (B)t1, (D)t2, (E)t3 );
}
else if(t3 instanceOf F) {
Function.F( (B)t1, (D)t2, (F)t3 );
}
}
}
}
}
The second solution can probably be further simplified using reflection.
I am not sure that I will answer your question, but I hope I can add a bit to the discussion. I will try to come back later with a more general answer, but in this one I will focus only on your example above.
The problem with the example given in the question is that it is based on arithmetical operations and that makes it inherently complex because the implementation of a given operator changes depending on the types of its operands.
I think that the problem obscures the question a little bit, e.g. we could spend time trying to make your example work instead of dealing with multiple dispatch issues.
One way to make your code work would be to think from a different point of view. Instead of defining an abstraction called Operator what we could do is to recognize the inherent nature of the operands, namely that they must provide an implementation of every possible operation that can affect them. In object-oriented terms, every operand packs a bunch of actions that can affect them.
And so, imagine I have an interface Operand like this, that defines every possible operation an operand supports. Notice that I not only defined one method variance per every possible known operand but also one method for a general case of another unknown operand:
interface Operand {
Operand neg();
Operand add(Int that);
Operand add(Decimal that);
Operand add(Operand that);
Operand mult(Int that);
Operand mult(Decimal that);
Operand mult(Operand that);
Operand sub(Int that);
Operand sub(Decimal that);
Operand sub(Operand that);
}
Then now consider that we had two implementations of this: Int and Decimal (I will use decimal instead of the matrix of your example for simplicity).
class Int implements Operand {
final int value;
Int(int value) { this.value = value; }
public Int neg(){ return new Int(-this.value); }
public Int add(Int that) { return new Int(this.value + that.value); }
public Decimal add(Decimal that) { return new Decimal(this.value + that.value); }
public Operand add(Operand that) { return that.add(this); } //!
public Int mult(Int that) { return new Int(this.value * that.value); }
public Decimal mult(Decimal that) { return new Decimal(this.value * that.value); }
public Operand mult(Operand that) { return that.mult(this); } //!
public Int sub(Int that) { return new Int(this.value - that.value); }
public Decimal sub(Decimal that) { return new Decimal(this.value - that.value); }
public Operand sub(Operand that) { return that.neg().add(this); } //!
public String toString() { return String.valueOf(this.value); }
}
class Decimal implements Operand {
final double value;
Decimal(double value) { this.value = value; }
public Decimal neg(){ return new Decimal(-this.value); }
public Decimal add(Int that) { return new Decimal(this.value + that.value); }
public Decimal add(Decimal that) { return new Decimal(this.value + that.value); }
public Operand add(Operand that) { return that.add(this); } //!
public Decimal mult(Int that) { return new Decimal(this.value * that.value); }
public Decimal mult(Decimal that) { return new Decimal(this.value * that.value); }
public Operand mult(Operand that) { return that.mult(this); } //!
public Decimal sub(Int that) { return new Decimal(this.value - that.value); }
public Decimal sub(Decimal that) { return new Decimal(this.value - that.value); }
public Operand sub(Operand that) { return that.neg().add(this); } //!
public String toString() { return String.valueOf(this.value); }
}
Then I can do this:
Operand a = new Int(10);
Operand b = new Int(10);
Operand c = new Decimal(10.0);
Operand d = new Int(20);
Operand x = a.mult(b).mult(c).mult(d);
Operand y = b.mult(a);
System.out.println(x); //yields 20000.0
System.out.println(y); //yields 100
Operand m = new Int(1);
Operand n = new Int(9);
Operand q = m.sub(n);
Operand t = n.sub(m);
System.out.println(q); //yields -8
System.out.println(t); //yeilds 8
The key points here are:
Every operand implementation works in a similar way to a visitor pattern, in the sense that every operand implementation contains a dispatch function for every possible combination that you can get.
The tricky part is the method that acts on any Operand. This is the place where we exploit the visitor dispatch power, because we know the exact type of this, but not the exact type of that, so we force the dispatch by doing that.method(this) and problem solved!
However, since we invert the order of the evaluation, this has a problem with arithmetic operations that are not commutative, like the subtraction. That's why I do subtraction using addition instead (i.e. 1-9 equates to 1 + -9). Since addition is commutative.
And there you have it. Now I kind of found a solution to the specific example, but I have not provided a good solution to the multiple dispatch problem you originally had. That's why I said the example was not good enough.
Perhaps you could provide a better example, like the one in the Wikipedia page for Multiple Dispatch.
However, I think the solution will probably always be, reduce the problem to a series of single dispatches solved with some sort of visitor pattern like the one I did. If I have time, I will try to give it a shot later to a more general answer and not just this specific example.
But hopefully this post helps to foster further discussion and with luck it is step in the direction of the actual answer.
uncle bob did this:
// visitor with triple dispatch. from a post to comp.object by robert martin http://www.oma.com
/*
In this case, we are actually using a triple dispatch, because we have two
types to resolve. The first dispatch is the virtual Collides function which
resolves the type of the object upon which Collides is called. The second
dispatch is the virtual Accept function which resolves the type of the
object passed into Collides. Now that we know the type of both objects, we
can call the appropriate global function to calculate the collision. This
is done by the third and final dispatch to the Visit function.
*/
interface AbstractShape
{
boolean Collides(final AbstractShape shape);
void Accept(ShapeVisitor visitor);
}
interface ShapeVisitor
{
abstract public void Visit(Rectangle rectangle);
abstract public void Visit(Triangle triangle);
}
class Rectangle implements AbstractShape
{
public boolean Collides(final AbstractShape shape)
{
RectangleVisitor visitor=new RectangleVisitor(this);
shape.Accept(visitor);
return visitor.result();
}
public void Accept(ShapeVisitor visitor)
{ visitor.Visit(this); } // visit Rectangle
}
class Triangle implements AbstractShape
{
public boolean Collides(final AbstractShape shape)
{
TriangleVisitor visitor=new TriangleVisitor(this);
shape.Accept(visitor);
return visitor.result();
}
public void Accept(ShapeVisitor visitor)
{ visitor.Visit(this); } // visit Triangle
}
class collision
{ // first dispatch
static boolean Collides(final Triangle t,final Triangle t2) { return true; }
static boolean Collides(final Rectangle r,final Triangle t) { return true; }
static boolean Collides(final Rectangle r,final Rectangle r2) { return true; }
}
// visitors.
class TriangleVisitor implements ShapeVisitor
{
TriangleVisitor(final Triangle triangle)
{ this.triangle=triangle; }
public void Visit(Rectangle rectangle)
{ result=collision.Collides(rectangle,triangle); }
public void Visit(Triangle triangle)
{ result=collision.Collides(triangle,this.triangle); }
boolean result() {return result; }
private boolean result=false;
private final Triangle triangle;
}
class RectangleVisitor implements ShapeVisitor
{
RectangleVisitor(final Rectangle rectangle)
{ this.rectangle=rectangle; }
public void Visit(Rectangle rectangle)
{ result=collision.Collides(rectangle,this.rectangle); }
public void Visit(Triangle triangle)
{ result=collision.Collides(rectangle,triangle); }
boolean result() {return result; }
private boolean result=false;
private final Rectangle rectangle;
}
public class MartinsVisitor
{
public static void main (String[] args)
{
Rectangle rectangle=new Rectangle();
ShapeVisitor visitor=new RectangleVisitor(rectangle);
AbstractShape shape=new Triangle();
shape.Accept(visitor);
}
}
Related
I have two types of objects that can perform a calculate() operation with either an int or a byte:
public class A {
public int calculate(int n) {...}
}
and
public class B {
public byte calculate(byte n) {...}
}
I want to have an ArrayList of objects that I can loop over calling the calculate method.
How do I do that, using an interface?
Considering the difference in the int/byte signature
Would something like this be a good approach?
public interface Calculatable {
int calculate(int number);
default byte calculate(byte number) {
return (byte) calculate((int) number);
}
}
Maybe using a 3-rd class and check based on type could be useful
public class TestCalc {
public static void main(String[] args) {
List<Object> l = new ArrayList<Object>();
l.add(Integer.valueOf(300));
l.add(Byte.valueOf("120"));
l.add(Integer.valueOf(1));
TestCalc tc = new TestCalc();
ComputeAB cab = tc.new ComputeAB();
for (Object o : l) {
System.out.println(cab.calculate(o) + ":" + cab.type);
}
}
class A {
public int calculate(int n) {
return n;
}
}
class B {
public byte calculate(byte n) {
return n;
}
}
class ComputeAB {
String type = "";
public Object calculate(Object o) {
if (o instanceof Integer) {
type = "int";
return new A().calculate((int) o);
}
type = "byte";
return new B().calculate((byte) o);
}
}
}
Output
300:int
120:byte
1:int
I'm working on a homework assignment, and I'm having a really hard time wrapping my head around how to compare two of the same subclass objects.
Basically I have this superclass Magnitude:
class Magnitude {
public boolean lessThan(Magnitude m) {
}
public boolean lessThanEqualTo(Magnitude m) {
}
public boolean equalTo(Magnitude m) {
}
public boolean greaterThan(Magnitude m) {
}
public boolean notEqual(Magnitude m) {
}
}
And then I have a subclass Currency that extends Magnitude ( I am only allowed to override the lessThan() method):
class Currency extends Magnitude {
double amount;
public Currency(double amt) {
this.amount = amt;
}
#Override
public boolean lessThan(Magnitude m) {
Currency other_currency = (Currency) m;
if (this.amount < other_currency.amount) {
return true;
}
else {
return false
}
}
public void print() {
System.out.println(amount);
}
}
What exactly is the way that I should implement these methods for the super and subclass so that I can compare 2 objects of the same subclass?
You can make use of the fact that you can call lessThan() also from m and use this as the other argument.
abstract class Magnitude {
public abstract boolean lessThan(Magnitude m);
public boolean lessThanEqualTo(Magnitude m) {
return this.lessThan(m) || this.equalTo(m);
}
public boolean equalTo(Magnitude m) {
return ((!this.lessThan(m))&&(!m.lessThan(this)));
}
public boolean greaterThan(Magnitude m) {
return m.lessThen(this);
}
public boolean notEqual(Magnitude m) {
return !this.equal(m);
}
}
You then need to have
class Currency extends Magnitude {
double amount;
public Currency(double amt) {
this.amount = amt;
}
#Override
public boolean lessThan(Magnitude m) {
Currency other_currency = (Currency) m;
if (this.amount < other_currency.amount) {
return true;
}
else {
return false
}
}
public void print() {
System.out.println(amount);
}
}
Simply rewrite the methods at the subclass.
Now, if you create two instances of the subclass and compare them, it'll use the subclass method
Currency c1 = new Currency();
Currency c2 = new Currency();
c1.lessThan(c2); //will call Currency.lessThan method
To use parent's class method, use this way
c1.lessThan((Magnitude) c2);
See this form more info.
If I understand your question correctly, you want to know how to implement and override the lessThan() method in your Currency class, knowing you can only compare currencies but not magnitudes, but what you receive is a Magnitude type parameter.
In that case, you need to check if the Magnitude object you received as a paramether is actually an instance of Currency wrapped in a Magnitude class. To do that, you use the instanceof comparison operator and then cast the object to Currency:
#Override
public boolean lessThan(Magnitude m) {
if(m instanceof Currency) {
return this.amount < ((Currency)m).amount;
} else {
throw new IllegalArgumentException("Parameter is not a Currency");
}
}
public interface MyFunc<T> {
boolean func(T v1, T v2);
}
public class HighTemp {
private int hTemp;
HighTemp(){
}
public HighTemp(int ht) {
this.hTemp = ht;
}
boolean sameTemp(HighTemp ht2){
return hTemp == ht2.hTemp;
}
boolean lessThanTemp(HighTemp ht2){
return hTemp < ht2.hTemp;
}
}
class InstMethWithObjRef {
static <T> int counter(T[] vals, MyFunc<T> f, T v){
int count = 0;
for (int i = 0; i < vals.length; i++) {
if(f.func(vals[i], v)) count++;
}
return count;
}
public static void main(String[] args) {
int count;
//Create an array of HighTemp objects.
HighTemp[] weekDayHighs = {new HighTemp(89), new HighTemp(82),
new HighTemp(90), new HighTemp(89),
new HighTemp(89), new HighTemp(91),
new HighTemp(84), new HighTemp(83)};
count = counter(weekDayHighs, HighTemp::lessThanTemp,new HighTemp(89));
System.out.println(count);
}
}
Please explain how
boolean sameTemp() is compatible with func() in Functional interface.
sameTemp() method got implemented on func() in Functional Interface.
count = counter(weekDayHighs, HighTemp::sameTemp, new HighTemp(89)); is working
Please Explain All points separately.
Equivalent lambda expression of HighTemp::lessThanTemp is
(highTemp1, highTemp2) -> {
return highTemp1.lessThanTemp(highTemp2);
}
This is one of the features of Java8 named Reference to an Instance Method of an Arbitrary Object of a Particular Type
Consider following example,
interface FIface<T> {
int testMethod(T a, T b);
}
class Test2 {
private String str;
Test2(String str) {
this.str = str;
}
int ok(Test2 test2) {
System.out.println("Currnet String : "+ this.str);//Refer to t1
System.out.println("Test String : "+test2.str);//Refer to t2
return 0;
}
}
public class Test {
public static <T> int checkCall(T t1, T t2, FIface<T> fiFace) {
//Here Test2 :: ok is equivalent to t1.ok(t2)
return fiFace.testMethod(t1, t2);
}
public static void main(String[] args) {
checkCall(new Test2("a"), new Test2("b"), Test2 :: ok);
}
}
OUTPUT
Currnet String : a
Test String : b
Note here that Test2 :: ok is valid for the call even ok method is not static.
When you call the method checkCall for the functional interface you still have two arguments which are t1 and t2 and for that valid lambda expression can have parameters as (Test t1, Test t2) so your method Test2 :: ok here becomes valid for the call. Internally it works this way t1.ok(t2).
So, fiFace.testMethod(t1, t2); will will invoke method as t1.ok(t2)
For starters I'm not a professional programmer. I too had a great difficulty in understanding the so called "Reference to an Instance Method of an Arbitrary Object of a Particular Type" I think this might be helpful for somebody who comes here from a google search.
I understood it a little bit with the help of lambda expressions.
In your code HighTemp::lessThanTemp as a Lambda expression would look like (x,y)->{x.lessThanTemp(y);} Replacing the method reference with this lambda expression would produce the same result. The above Lambda expression or the method reference both tell the interface method what to do.
When you use the method reference it tells the interface method to use the referred method from the given class, to carryout its function. Therefore if you convert HighTemp::lessThanTemp to English words it would sound something like "implement the lessThanTemp method form the class HighTemp as the implementation of the interface function". As you might've noticed in that case the return types and the argument types should be compatible. Otherwise you cannot implement an interface.
I would provide you another simple example code. More examples helps to understand this concept.
interface myint{
int returnit(Test t ,int y);
}
class Test{
int x=0;
public Test(int x){
this.x=x;
}
public int addNumbers(int y){
return x+y;
}
public int subtractNumbers(int y){
return x-y;
}
}
public class myclass{
private static void myMethod(Test t,myint inf,int y){
int x=inf.returnit(t, y);
System.out.println(x+"");
}
public static void main(String[] args){
myMethod(new Test(4),Test::addNumbers,7);
myMethod(new Test(4),Test::subtractNumbers,7);
}
}
Output would be:
11
-3
This is the simplest way I could imagine it. See how return types and argument types gets matched using the above sentence pattern. Spend some time on it.
This is the Interface
package learninglambdaexp;
#FunctionalInterface
public interface TempInterface {
public boolean validTemp(Temperature temp);
}
This is the class
package learninglambdaexp;
public class Temperature {
private int temp;
public Temperature(int temp) {
this.temp = temp;
}
public boolean isEvenTemp() {
return temp % 2 == 0;
}
public boolean isOddTemp(){
return !isEvenTemp();
}
}
This is the Class with the Main Method
package learninglambdaexp;
import java.util.ArrayList;
import java.util.List;
public class AnotherMainClass {
public static void main(String[] args) {
List<Temperature> tempCollection = new ArrayList<>();
tempCollection.add(new Temperature(100));
tempCollection.add(new Temperature(20));
tempCollection.add(new Temperature(30));
tempCollection.add(new Temperature(40));
tempCollection.add(new Temperature(50));
tempCollection.add(new Temperature(60));
tempCollection.add(new Temperature(70));
int k1 = countVariation(tempCollection, Temperature::isEvenTemp);
//int k2 = countVariation(Temperature::lowTemp);
System.out.println(k1);
// System.out.println(k2);
}
private static int countVariation(List<Temperature> tempCollection, TempInterface ti) {
int count = 0;
for (Temperature eachTemp : tempCollection) {
if (ti.validTemp(eachTemp)) { // (eachTemp) -> {return eachTemp.isEvenTemp();};
count++;
}
}
return count;
}
}
With one argument its easier to understand
Please, correct me if I am wrong, but the way I think about this type of method references (Reference to an Instance Method of an Arbitrary Object of a Particular Type) is that when we pass a method reference, in this case to the counter method, the instance of anonymous class which implements MyFunc interface is created. Then, inside this anonymous class, we override func method which is passed two parameters. And then inside the func method, lessThanTemp method is called like this:
v1.lessThanTemp(v2);
So for me this concept looks something like this:
public class Demo {
public static void main(String[] args) {
AnonymousClass an = new AnonymousClass();
System.out.println(an.apply(new SomeClass(3), 4));
}
}
interface SomeInterface {
int apply(SomeClass obj, int n);
}
class SomeClass {
private int n;
SomeClass(int n) {
this.n = n;
}
int add(int n) {
return this.n + n;
}
}
class AnonymousClass implements SomeInterface {
#Override
public int apply(SomeClass o, int n) {
return o.add(n);
}
}
I want to write a method in java which receives an array of objects, checks for some compatibility and return a boolean value true if all meet, otherwise to return a string containing a message to inform user why some of the compatibilities don't meet.
I came up with simplified version of my question as follows:
Suppose you wanna compare cars and in order that comparison make sense you wanna make sure all are of same class, same color, same make.
So what I am trying to get from this method are two:
1- are all care compatible? (boolean using return)
2- if not, why? so to inform user of the reasons(String using throw)
What is the best design pattern for this?
Below is one way of implementing it:
boolean areCarsCompatible(Car [] cars) throws CarException {
String errorMessage = "";
for(Car car:cars){
if (cars done have same color) errorMessage +="Cars dont have same color";
}
for(Car car:cars){
if (cars done have same make) errorMessage +="Cars dont have same make";
}
for(Car car:cars){
if (cars are not all of same class) errorMessage +="cars are not all of same class";
}
if (errorMessage.equals("")){
return true
} else {
throw new CarException (errorMessage);
}
}
to return both boolean and strings
Although you can do this in other (dynamic) programming languages, it's strongly recommended that you don't design your method like this in Java. In Java, types are statically checked and strict, you simply can't return two different types from the same method, and throwing an exception when you intend to return a string is, well, just an ugly hack.
A different matter would be throwing an exception with a message to indicate an error, that's a very common practice and within the good practices of the language. But notice that you wouldn't be "returning both boolean and strings", an exception is intended for error handling.
There is a lot to address here.
First, you are seeking a design, an approach, an algorithm, etc., but please don't call this a design pattern. That term has a very specific meaning.
OK, nitpicking semantics aside, your approach is a bit awkward for a couple of reasons. First, the boolean is sort of useless because you don't care about "falseness." Either it all works, or you get a message of some kind. The value false has no value for you.
The other reason it is awkward is as #OscarLopez suggests. There is no neat way in Java, as in Ruby for example, to return a multi-type value.
I will say though that if you are going to throw an exception, your CarException is getting close to the right approach--if it is a checked exception as it seems. I strongly disagree with #cherouvim (though I didn't downvote) that it should be a RuntimeException. You want the caller to know about it and to have to deal with it.
As for my own suggestions for solutions, I have two:
1) Maintain some notion of the criteria necessary for a Car to be in the collection. Then simply don't add a Car to the collection if it doesn't meet those criteria. In other words, solve the problem by preventing it from ever happening in the first place.
2) Use Enums.
public enum CarFeedback {
ALL_SAME, DIFFERENT_COLORS, DIFFERENT_MAKES, DIFFERENT_CLASSES
}
public CarFeedback checkCars(List<Car> cars) {
//Do checks
return ALL_SAME; //or whichever enum value is appropriate
}
Your method can be void and throw an exception if there are any problems. There is no need for it to return a boolean. The caller should assume that if no exception was thrown then everything is OK. This is exactly how exceptions were designed to be used.
I would rename the method:
void checkCompatibilityOf(Car... cars) throws IncompatibleCarsException
Alternative approach: Inversion of Control
Rather than returning a value from the method, you can ask the method to callback with its answer(s). E.g.
interface CompatibilityListener {
void onSuccess();
void onFailure(String message);
}
This will avoid the need for a boolean return value, and remove the need for exceptions.
You could go further and extract the logic of building the error message too:
interface DifferenceListener {
void onDifferentColor(Car car1, Car car2);
void onDifferentMake(Car car1, Car car2);
//etc.
}
And this method:
public void checkCompatibilityOf(DifferenceListener listener, Cars... cars) {
for (Car car: cars) {
if (...) {
listener.onDifferentColor(car1, car2);
}
if (...) {
listener.onDifferentMake(car1, car2);
}
// etc.
}
}
Inversion of control can be a powerful approach in some cases, although, as Vidya says (in the comment) it's probably over-engineering in your case!
You can do everything you want with JAVA. You can create your own class to get the object with any included values you prefer. See below :
import java.math.BigInteger;
import java.util.Date;
public class BoolVariable {
private static BoolVariable instance;
public static BoolVariable BOOLVARIABLE = getInstance();
private boolean bool;
private char c;
private String s;
private int i;
private double d;
private float f;
private BigInteger bi;
private Date date;
private static BoolVariable getInstance() {
if (instance == null) {
instance = new BoolVariable();
}
return instance;
}
private BoolVariable() {
}
public BoolVariable(boolean bool, char c) {
this.bool = bool;
this.c = c;
}
public BoolVariable(boolean bool, String s) {
this.bool = bool;
this.s = s;
}
public BoolVariable(boolean bool, int i) {
this.bool = bool;
this.i = i;
}
public BoolVariable(boolean bool, double d) {
this.bool = bool;
this.d = d;
}
public BoolVariable(boolean bool, float f) {
this.bool = bool;
this.f = f;
}
public BoolVariable(boolean bool, BigInteger bi) {
this.bool = bool;
this.bi = bi;
}
public BoolVariable(boolean bool, Date date) {
this.bool = bool;
this.date = date;
}
public boolean getBool() {
return bool;
}
public char getC() {
return c;
}
public String getS() {
return s;
}
public int getI() {
return i;
}
public double getD() {
return d;
}
public float getF() {
return f;
}
public BigInteger getBi() {
return bi;
}
public Date getDate() {
return date;
}
public void setBool(boolean bool) {
this.bool = bool;
}
public void setC(char c) {
this.c = c;
}
public void setS(String s) {
this.s = s;
}
public void setI(int i) {
this.i = i;
}
public void setD(double d) {
this.d = d;
}
public void setF(float f) {
this.f = f;
}
public void setBi(BigInteger bi) {
this.bi = bi;
}
public void setDate(Date date) {
this.date = date;
}
public BoolVariable create(boolean bool, char c){
return new BoolVariable(bool, c);
}
public BoolVariable create(boolean bool, String s){
return new BoolVariable(bool, s);
}
public BoolVariable create(boolean bool, int i){
return new BoolVariable(bool, i);
}
public BoolVariable create(boolean bool, double d){
return new BoolVariable(bool, d);
}
public BoolVariable create(boolean bool, float f){
return new BoolVariable(bool, f);
}
public BoolVariable create(boolean bool, BigInteger bi){
return new BoolVariable(bool, bi);
}
public BoolVariable create(boolean bool, Date date){
return new BoolVariable(bool, date);
}
#Override
public String toString() {
return "BoolVariable{" + "bool=" + bool + ", c=" + c + ", s="
+ s + ", i=" + i + ", d=" + d + ", f=" + f + ", bi="
+ bi + ", date=" + date + '}';
}
}
You can call this class in any routine that you want to get double variable like below:
BoolVariable bv = BOOLVARIABLE.create(true, "HERE IS YOUR VARIABLE LIKE INTEGER, STRING ETC");
So then you can get any value like bv.getBool();
One idea is to always return boolean but if a condition is not met then you throw a flavour of RuntimeException describing the problem. The caller of this method should handle that.
I know this question is pretty old but I still think this method will clear up a lot of things given the nature of the question. Particularly where it says "... a method in java which receives an array of objects, checks for some compatibility and return a boolean value true if all meet, otherwise to return a string containing a message to inform user why some of the compatibilities don't meet ..." Judging from the question incompatible cars are not supposed to be an error, it is actually as per design part of the behavior of the program, meaning that the car can be compatible or not and from what you want to do you want to know why it is not compatible. If all my current assumptions are right I would rather write my method to return Boolean and incase the method returns a false cause the cars do not match I create a local methods and property in my class getCompareErrorMsg() and compare_error_msg before returning the false in this given method I set the compare_error_msg to the exact comparison error msg, which from what I understand from your question was what you wanted to return as string. so the caller of the method check for it's Boolean value, if it is false the caller can call the method getCompareErrorMsg() which actually returns a string and do what ever it wants to do with it.
So, after playing around with Java generics a bit, to get a deeper understanding of their capabilities, I decided to try to implement the curried version of the composition function, familiar to functional programmers. Compose has the type (in functional languages) (b -> c) -> (a -> b) -> (a -> c). Doing currying arithmetic functions wasn't too hard, since they are just polymorphic, but compose is a higher order function, and its proven taxing to my understanding of generics in Java.
Here is the implementation I've created so far:
public class Currying {
public static void main(String[] argv){
// Basic usage of currying
System.out.println(add().ap(3).ap(4));
// Next, lets try (3 * 4) + 2
// First lets create the (+2) function...
Fn<Integer, Integer> plus2 = add().ap(2);
// next, the times 3 function
Fn<Integer, Integer> times3 = mult().ap(3);
// now we compose them into a multiply by 2 and add 3 function
Fn<Integer, Integer> times3plus2 = compose().ap(plus2).ap(times3);
// now we can put in the final argument and print the result
// without compose:
System.out.println(plus2.ap(times3.ap(4)));
// with compose:
System.out.println(times3plus2.ap(new Integer(4)));
}
public static <A,B,C>
Fn<Fn<B,C>, // (b -> c) -> -- f
Fn<Fn<A,B>, // (a -> b) -> -- g
Fn<A,C>>> // (a -> c)
compose(){
return new Fn<Fn<B,C>,
Fn<Fn<A,B>,
Fn<A,C>>> () {
public Fn<Fn<A,B>,
Fn<A,C>> ap(final Fn<B,C> f){
return new Fn<Fn<A,B>,
Fn<A,C>>() {
public Fn<A,C> ap(final Fn<A,B> g){
return new Fn<A,C>(){
public C ap(final A a){
return f.ap(g.ap(a));
}
};
}
};
}
};
}
// curried addition
public static Fn<Integer, Fn<Integer, Integer>> add(){
return new Fn<Integer, Fn<Integer, Integer>>(){
public Fn<Integer,Integer> ap(final Integer a) {
return new Fn<Integer, Integer>() {
public Integer ap(final Integer b){
return a + b;
}
};
}
};
}
// curried multiplication
public static Fn<Integer, Fn<Integer, Integer>> mult(){
return new Fn<Integer, Fn<Integer, Integer>>(){
public Fn<Integer,Integer> ap(final Integer a) {
return new Fn<Integer, Integer>() {
public Integer ap(final Integer b){
return a * b;
}
};
}
};
}
}
interface Fn<A, B> {
public B ap(final A a);
}
The implementations of add, mult, and compose all compile just fine, but I find myself having a problem when it comes to actually using compose. I get the following error for line 12 (the first usage of compose in main):
Currying.java:12: ap(Fn<java.lang.Object,java.lang.Object>) in
Fn<Fn<java.lang.Object,java.lang.Object>,Fn<Fn<java.lang.Object,java.lang.Object>,Fn<java.lang.Object,java.lang.Object>>>
cannot be applied to (Fn<java.lang.Integer,java.lang.Integer>)
Fn<Integer,Integer> times3plus2 = compose().ap(plus2).ap(times3);
I assume this error is because generic types are invariant, but I am not sure how to solve the problem. From what I've read, wildcard type variables can be used to alleviate invariance in some cases, but I'm not sure how to use it here or even whether it will be useful.
Disclaimer: I have no intention of writing code like this in any real project. This is a fun "can it be done" kind of thing. Also, I made the variable names brief in defiance of standard Java practice because otherwise this example becomes an even more of an incomprehensible wall of text.
The basic problem here is that in the original call to compose(), there is no way for the compiler to infer the bindings of A, B, and C, so it assumes them all to be Object. You can fix it by specifying the type bindings explicitly:
Fn<Integer, Integer> times3plus2 =
Currying.<Integer, Integer, Integer>compose().ap(plus2).ap(times3);
Of course, then you lose the clarity that comes from type inference. If you need type inference, you could define some intermediate classes to do the inferring:
public static ComposeStart compose() {
return new ComposeStart();
}
class ComposeStart {
public <B,C> ComposeContinuation<B,C> ap(Fn<B,C> f) {
return new ComposeContinuation<B, C>(f);
}
}
class ComposeContinuation<B, C> {
private final Fn<B,C> f;
ComposeContinuation(Fn<B,C> f) {
this.f = f;
}
public <A> Fn<A,C> ap(final Fn<A,B> g) {
return new Fn<A,C>() {
public C ap(A a) {
return f.ap(g.ap(a));
}
};
}
}
However, then the intermediate steps of currying are no longer Fns.
Thanks to Russell Zahniser's insight that I wasn't giving Java enough information to work with, I changed the layout a bit so that we instantiate a "Composer" object with the appropriate type variables filled in. Here is my current working solution:
interface Fn<A, B> {
public B ap(final A a);
}
public class Currying {
public static void main(String[] argv){
// Basic usage of currying
System.out.println(add().ap(3).ap(4));
// Next, lets try (3 * 4) + 2
// First lets create the (+2) function...
Fn<Integer, Integer> plus2 = add().ap(2);
// next, the times 3 function
Fn<Integer, Integer> times3 = mult().ap(3);
// now we compose them into a multiply by 2 and add 3 function
Fn<Integer, Integer> times3plus2 = new Composer<Integer,Integer,Integer>()
.compose().ap(plus2).ap(times3);
// without compose
System.out.println(plus2.ap(times3.ap(4)));
// with compose
System.out.println(times3plus2.ap(4));
}
static class Composer<A,B,C> {
public
Fn<Fn<B,C>, // (b -> c) -> -- f
Fn<Fn<A,B>, // (a -> b) -> -- g
Fn<A,C>>> // (a -> c)
compose(){
return new Fn<Fn<B,C>,
Fn<Fn<A,B>,
Fn<A,C>>> () {
public Fn<Fn<A,B>,
Fn<A,C>> ap(final Fn<B,C> f){
return new Fn<Fn<A,B>,
Fn<A,C>>() {
public Fn<A,C> ap(final Fn<A,B> g){
return new Fn<A,C>(){
public C ap(final A a){
return f.ap(g.ap(a));
}
};
}
};
}
};
}
}
public static Fn<Integer, Fn<Integer, Integer>> add(){
return new Fn<Integer, Fn<Integer, Integer>>(){
public Fn<Integer,Integer> ap(final Integer a) {
return new Fn<Integer, Integer>() {
public Integer ap(final Integer b){
return a + b;
}
};
}
};
}
public static Fn<Integer, Fn<Integer, Integer>> mult(){
return new Fn<Integer, Fn<Integer, Integer>>(){
public Fn<Integer,Integer> ap(final Integer a) {
return new Fn<Integer, Integer>() {
public Integer ap(final Integer b){
return a * b;
}
};
}
};
}
}
I've implemented this functionality myself in terms of a generic length-n chain of function calls.
public static final <X, Y> Chainer<X, Y> chain(
final Function<X, Y> primary
) {
return new Chainer<X, Y>(primary);
}
private static final class FunctionChain<IN, OUT> implements Function<IN, OUT> {
#SuppressWarnings("rawtypes")
private final List<Function> chain = new LinkedList<Function>();
private FunctionChain(#SuppressWarnings("rawtypes") final List<Function> chain) {
this.chain.addAll(chain);
}
#SuppressWarnings("unchecked")
#Override
public OUT apply(final IN in) {
Object ret = in;
for (final Function<Object, Object> f : chain) {
ret = f.apply(ret);
}
return (OUT) ret;
}
}
public static final class Chainer<IN, OUT> {
#SuppressWarnings("rawtypes")
private final LinkedList<Function> functions = new LinkedList<Function>();
#SuppressWarnings("unchecked")
private Chainer(#SuppressWarnings("rawtypes") final Function func) {
then(func);
}
#SuppressWarnings("unchecked")
public <OUT2> Chainer<IN, OUT2> then(final Function<OUT, OUT2> func) {
if (func instanceof FunctionChain) {
functions.addAll(((FunctionChain<?, ?>)func).chain);
} else {
functions.add(func);
}
return (Chainer<IN, OUT2>) this;
}
#SuppressWarnings("unchecked")
public Function<IN, OUT> build() {
// If empty, it's a noop function. If one element, there's no need for a chain.
return new FunctionChain<IN, OUT>(functions);
}
}
public static final <X, Y, Z> Function<X, Z> combine(
final Function<X, Y> primary,
final Function<Y, Z> secondary
) {
return chain(primary).then(secondary).build();
}
I would contend that this qualifies as a greater abuse of generics, since the Chainer class only uses generics to ensure that subsequent .then() calls are properly typed based on the last function supplied, and the functions are just stored in a list in what is known to be a safe calling order for later, but it does work and it does generalize well: chain(first).then(second).then(third).then(fourth).build() is completely valid with this approach.
Just be be explicit, this is based around Function from guava, but should port over to any Function interface just fine.