1

This is something I ran into trying to solve someone else's question here, in a simplified version. Client and Server with reflexive (circular) dependency use generics to try to keep strongly typed references in super class. The wish was for arbitrary sub-type parings such as ClientType1<->ServerType2 , and for strongly typed calls on specialized methods found only in a specific type.

This only works for one level of depth: from server to client, but fails if you then try to continue from that client back to the server: Is there any syntax which would allow arbitrary levels of strongly typed calls?

abstract class ServerBase<C extends ClientBase<?>>
{
    ArrayList<C> clients = new ArrayList<C>();
}
abstract class ClientBase<S extends ServerBase<?>>
{
    S server;
}
class ClientType1<S extends ServerBase<?>> extends ClientBase<S>
{
    public void clientType1Method() {}
}

class ServerType1<C extends ClientBase<?>> extends ServerBase<C>
{

}



public class Example {
     public static void main(String[] args) {
        ServerType1<ClientType1<?>> s = new ServerType1<>();
        s.clients.get(0).clientType1Method(); // Single depth level - OK
        s.clients.get(0).server.clients.get(0).clientType1Method(); // level 2 - compiler error - undefined method      
     }
}

3 Answers 3

2

In my opinion you should not actually need such an intricate reference.

What you really mean is that the client has to hold a reference to a server it can connect, and viceversa.

what should work is:

abstract class ServerBase<C extends ClientBase<? extends ServerBase>>
{
    ArrayList<C> clients = new ArrayList<C>();
}
abstract class ClientBase<S extends ServerBase<? extends ClientBase>>
{
    S server;
}
Sign up to request clarification or add additional context in comments.

Comments

1

If you do a small tweak with this code it will surely work.

abstract class ClientBase<S extends ServerBase<?>> {
    S server;

    public abstract void clientMethod();
}

.......

public static void main(String[] args) {
    ServerType1<ClientBase<?>> s = new ServerType1<>();
    s.clients.get(0).clientMethod(); // Single depth level - OK

    s.clients.get(0).server.clients.get(0).clientMethod(); 
    // second  level - NO compiler error
}

1 Comment

Thanks, although that was not the meaning. It should work for arbitrary levels, and the clientMethod is supposed to be a unique in each derived class (e.g. different name or signature )
0

Well, it fails because you have entered yourself a ? instead of an actual type. If you use

ServerType1<ClientType1<ServerType1<ClientType1<?>>>> s = new ServerType1<>();
s.clients.get(0).clientType1Method();
s.clients.get(0).server.clients.get(0).clientType1Method();

instead, it will work. Though it is quite pointless, if we assume that s.clients.get(0).server is the same as s.

Having a circular dependency works only, if you have named types you can refer to, e.g.

public static <S extends ServerType1<ClientType1<S>>> void main(String[] args) {
    ServerType1<ClientType1<S>> s = new ServerType1<>();
    s.clients.get(0).clientType1Method();
    s.clients.get(0).server.clients.get(0).clientType1Method();
    s.clients.get(0).server.clients.get(0).server.clients.get(0).clientType1Method();
    s.clients.get(0).server.clients.get(0).server.clients.get(0)
                    .server.clients.get(0).clientType1Method();
    s.clients.get(0).server.clients.get(0).server.clients.get(0)
                    .server.clients.get(0).server.clients.get(0).clientType1Method();
}

Though this is likely to be impractical for most use cases. As soon as you end up having to instantiate S, you would need a real class instead. You should rethink whether you really need such a generic construct. And if you really consider creating such code with helper type variables that are irrelevant to the method’s caller, you should do that with private methods, to avoid them being visible in the public API of your class.

4 Comments

It does not compile.
Well, it does with my jdk. If you get a compile error, you should post the error, or even better, try to understand the code (that’s the purpose of posting code in an answer to your question) and tell me, what’s wrong with it.
This is a type parameter. You should understand what a type parameter is, as you are asking a question about Generics. Just copy the method exactly as posted and it does compile.
The code does compile. There is no “garbage” anywhere. You still failed to post what actual compiler error occurs. You are the one asking for help here. That’s not an opinion, that’s a fact. End of conversation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.