views:

165

answers:

2

I am writing an application to do some distributed calculations in a peer to peer network. In defining the network I have two class the P2PNetwork and P2PClient. I want these to be generic and so have the definitions of:

P2PNetwork<T extends P2PClient<? extends P2PNetwork<T>>>

P2PClient<T extends P2PNetwork<? extends T>>

with P2PClient defining a method of setNetwork(T network). What I am hoping to describe with this code is:

  1. A P2PNetwork is constituted of clients of a certain type
  2. A P2PClient may only belong to a network whose clients consist of the same type as this client (the circular-reference)

This seems correct to me but if I try to create a non-generic version such as

MyP2PClient<MyP2PNetwork<? extends MyP2PClient>> myClient;

and other variants I receive numerous errors from the compiler. So my questions are as follows:

  1. Is a generic circular reference even possible (I have never seen anything explicitly forbidding it)?
  2. Is the above generic definition a correct definition of such a circular relationship?
  3. If it is valid, is it the "correct" way to describe such a relationship (i.e. is there another valid definition, which is stylistically preferred)?
  4. How would I properly define a non-generic instance of a Client and Server given the proper generic definition?
+2  A: 

It might help us to answer you if you further defined what "a certain type" means, i.e. what the differences are between various "types" of P2PNetworks.

But instead of expressing the dependency / circular relationship in terms of each other, it might be easier to express by introducing a third class, the P2PType:

public class P2PNetwork<T extends P2PType> {
    ...
}
public class P2PClient<T extends P2PType> {
    ...
    public void setNetwork(P2PNetwork<T> network) { ... }
}

I might be overlooking something but I think this would allow the compiler to enforce that P2PClients are a part of P2PNetworks of the same generic type.

This approach might fall apart however if the "type" isn't something that is suitable to express as a object-oriented itself, i.e. if the P2PType isn't something that would have methods, polymorphic behavior, etc.

matt b
The thought is type is the purpose of the network. A contrived example: a network for calculating Fibbonnacci numbers vs. Prime numbers vs determining the meaning of life. The premise is the base Network class is responsible for maintain the state and connectedness of the network, the base client for propagating the information about the network and handling the actual task of the network. That said this has also become an academic interest as to if circular generic definitions are possible, and if so how they would achieved.
M. Jessup
+3  A: 

Circular generic references are indeed possible. Java Generics and Collections includes several examples. For your case, such a specimen would look like this:

public interface P2PNetwork<N extends P2PNetwork<N, C>,
                            C extends P2PClient<N, C>> {
  void addClient(C client);
}

public interface P2PClient<N extends P2PNetwork<N, C>,
                            C extends P2PClient<N, C>> {
  void setNetwork(N network);
}

class TorrentNetwork implements P2PNetwork<TorrentNetwork, TorrentClient> {
  @Override
  public void addClient(TorrentClient client) {
    ...
  }
}

class TorrentClient implements P2PClient<TorrentNetwork, TorrentClient> {
  @Override
  public void setNetwork(TorrentNetwork network) {
    ...
  }
}

...

TorrentNetwork network = new TorrentNetwork();
TorrentClient client = new TorrentClient();

network.addClient(client);
Péter Török