3 Replies Latest reply on Jul 24, 2010 8:24 AM by EJP

    Interface Adapter Class and Subclass Return Type

    843793
      In the following code I had to add "<T extends ArgAdapter>" to the abstract class AND then pass the subclass name as the value of "T" in order for the code to work correctly.

      1) why do I have to do the cast "return (T) this" in the "reset()" method of the adapter class?

      2) Is it "safe" to do this?
      I assume it is safe, since any instance of ArgAdapter must be a subclass of it, and "T" is restricted so that it extends the adapter class.
      Could there be problems w/ that assumption?

      3) is there any other way to declare the ArgAdapter class and/or it's "reset()" method so the subclass wouldn't have to pass in it's own class name?
      public class Junk {
      
          // interfaces
          public interface Arg{
              public Arg reset();
          }
          public abstract class ArgAdapter<T extends ArgAdapter> implements Arg{
              public T reset() { return (T) this; } // Could this cast be a problem?
          }
          public interface Processor<T extends Arg>{
              public void process( T arg );
          }
      
      
          // implementors
          public class MyArg extends ArgAdapter<MyArg>{ // Must use "<MyArg>"
              public String someMethod(){
                  return "hello";
              }
              // Without "<T extends ArgAdapter>" this works, but defeats the purpose of using an adapter class
              // public MyArg reset() {
              //    return this;
              // }
          }
          public class MyProcessor implements Processor<MyArg>{
              public void process( MyArg arg ){
                  String str = arg.someMethod();
                  // do something with "str"
              }
          }
      
      
          // example usage
          public void example(){
              MyArg arg = new MyArg();
              Processor<MyArg> proc = new MyProcessor();
      
              // THIS IS OK
              proc.process( arg );
      
              // Without "<T extends ArgAdapter>" this won't compile
              // -- process(Junk.MyArg) in Junk.Processor<Junk.MyArg> cannot be applied to (Junk.Arg)
              proc.process( arg.reset() );
      
          }
      }
        • 1. Re: Interface Adapter Class and Subclass Return Type
          EJP
          1) why do I have to do the cast "return (T) this" in the "reset()" method of the adapter class?
          Because 'this' is of type ArgAdapter. The compiler has no way of knowing that it's a T. In fact it mightn't be!
          2) Is it "safe" to do this?
          I assume it is safe, since any instance of ArgAdapter must be a subclass of it, and "T" is restricted so that it extends the adapter class.
          That doesn't follow at all. Rethink that. Consider MyArgAdapter<MyOtherArgAdapter>.

          It's a strange design. I'm sure there's a better way. Possibly without Generics at all. Did you consider return type covariance?
          • 2. Re: Interface Adapter Class and Subclass Return Type
            843793
            ejp wrote:
            1) why do I have to do the cast "return (T) this" in the "reset()" method of the adapter class?
            Because 'this' is of type ArgAdapter. The compiler has no way of knowing that it's a T. In fact it mightn't be!
            I agree that "this" is an instance of ArgAdapter in the "reset()" method.
            The class is abstract and "T" is declared to "extend ArgAdapter".
            Unless somehow there are 2 different definitions for ArgAdapter in the jvm (one abstract, the other not), if a thread is in the "reset()" method then "this" is actually an instance of a subclass of ArgAdapter... right?
            Maybe I was just expecting too much of the compiler to figure that out.

            But I may be confused on that.
            If I declare "<T extends ArgAdapter>" doesn't that mean that "T" must be a subclass of "ArgAdapter"?
            2) Is it "safe" to do this?
            I assume it is safe, since any instance of ArgAdapter must be a subclass of it, and "T" is restricted so that it extends the adapter class.
            That doesn't follow at all. Rethink that. Consider MyArgAdapter<MyOtherArgAdapter>.
            I'm not sure what you mean by this... are you saying if I declare 2 other classes MyArgAdapter and MyOtherArgAdapter (which extends MyArgAdapter) or ... ??
            Perhaps you mean "MyArgAdapter" is not a subclass of "ArgAdapter", but is just another unrelated class that also implements "Arg"... ??
            It's a strange design. I'm sure there's a better way. Possibly without Generics at all. Did you consider return type covariance?
            Yes, it is probably a strange design :-)

            The thing is the type of "Processor" is tied to the type of "Arg" that is used when it "processes" whatever it needs to process.
            There may be specific methods or whatever on the "Arg" instance that the processor needs to call.

            So if I have MyOtherProcessor it would most likely be tied to another type of "Arg" (say "MyOtherArg") and would not be able to use "MyArg".

            I was hoping that generics would prevent having to typecast stuff as would be needed if return type covariance is used.
            Further return type covariance would make the adapter class with "default" methods pointless, because you would need to define the "reset()" method for each subclass.
            (At least that is the way I understand it.)

            Please tell me if I have any of this wrong; I am trying to learn more about using generics.
            • 3. Re: Interface Adapter Class and Subclass Return Type
              EJP
              Unless somehow there are 2 different definitions for ArgAdapter in the jvm (one abstract, the other not), if a thread is in the "reset()" method then "this" is actually an instance of a subclass of ArgAdapter... right?
              How is the compiler supposed to know there will be no other extensions of ArgAdapter?
              Maybe I was just expecting too much of the compiler to figure that out.
              Somewhat.
              But I may be confused on that.
              You are wrong about that. The compiler can't possibly make that assumption.
              That doesn't follow at all. Rethink that. Consider MyArgAdapter<MyOtherArgAdapter.
              > I'm not sure what you mean by this... are you saying if I declare 2 other classes MyArgAdapter and MyOtherArgAdapter (which extends MyArgAdapter)
              I'm saying that the compiler is aware of that possibility and that there Is no mechanism for excluding it.
              Perhaps you mean "MyArgAdapter" is not a subclass of "ArgAdapter", but is just another unrelated class that also implements "Arg"... ??
              I meant what I said.
              I was hoping that generics would prevent having to typecast stuff as would be needed if return type covariance is used.
              No it wouldn't.
              you would need to define the "reset()" method for each subclass.
              Now that's correct. But you can't have it both ways. There's no typecast involved in that.