views:

200

answers:

5

Basically I want to do this:

public interface A {
    void a();
}
public interface B {
    void b();
}
public class SomeClass {
    public SomeClass(<A&B> e) { // Note the type here
        e.a();
        e.b();
    }
}

What I did on the commented line is obviously illegal. I know I can just require the passed object to implement interface A, or interface B, but is there a way to do both?

I guess there are workarounds (like requiring the parameter to be of type A and then check if it is also an instanceof B), but that way I don't get help from the compiler. Do you know of any way to do this? Or maybe a smarter workaround...

+15  A: 

You can do it with generics enabled. For example, to accept an instance of some class that implements both CharSequence and Appendable:

  public <T extends CharSequence & Appendable> void someMethod(T param) {
    ...
  }
Neil Coffey
This feels messy since you still need to define a type T which implements both A and B. Why not just make that the paramater type? If many objects implement A and B why not make an interface C : A, B?
Joseph Daigle
+3  A: 

Depending on the design, you can do one of the following:

  1. Make A : B or B : A.
  2. Make an interface C : A, B.

Either way you'll want to have contract that includes both a() and b().

Joseph Daigle
Thanks, but the inheritance option doesn't always make sense (A and B could be totally unrelated. I don't really like the second option either, because it means that 1) I might have to make 'C interfaces' for every possible combination of interfaces and 2) classes should all implement these...
Jordi
Like I said, it depends on the design. If A and B were related then 1) would work. 2) Really sin't so bad though. A anb B are somewhat related because you're passing in an object that implements both. What about a base class that implements both?
Joseph Daigle
+1  A: 

Just shooting in the dark, I don't know if this is the correct syntax, ie if you have to redeclare the methods in C but what about this:

public interface A {
    void a();
}
public interface B {
    void b();
}

public interface C extends A, B{}

public class SomeClass{
    public SomeClass(C e) { // Note the type here
      e.a();
      e.b();
    }

}
scottm
This requires classes to extend C if their values need to be used as parameters here. A type isn't a subtype of an interface just by implementing the correct methods; it must be explicitly marked.
Jay Conrod
You are right that this does require classes to extend C which also means they've extended A and B. I was under the impression that this was supposed to be class SomeClass that had a method that required a variable type of another class that implemented both A and B. So I created C for that contract
scottm
+3  A: 

Well, there is the <T extends A & B> f(T ab) notation, but you should favour composition over inheritance. You don't really have to extend anything. Just make a type that is the joint union (product) of both types A and B, as follows:

public abstract class P2<A, B> {
  public A _1();
  public B _2();
}

Sometimes called a product-2, or a "pair" type. You can create a handy constructor for these:

public final class P {
  private P() {}
  public static <A, B> P2 p(final A a, final B b) {
    return new P2<A, B>() {
      public A _1() {
        return a;
      }
      public B _2() {
        return b;
      }
    }
  }
}

Note that you can use the same object for both arguments, if A and B are interfaces and your object implements both of them:

P2<A, B> both = P.p(o, o);

Or you're free to use two different objects, making the design nice and decoupled.

You'll find this type, as well as products of up to 8 types, included in the Functional Java library. There's also a type called Either<A, B> that is the disjoint union (sum) of two types, such that it holds a value that is of either type A or B (or both).

Apocalisp
A: 

If you have a method that needs two different interfaces as parameters, just make it take two parameters.

public void foo(A a, B b) {
    ....
}

It’s not that hard, believe me.

Bombe