Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function with generic type as member variable

Tags:

java

generics

I have a function which maps a class object to an instance of this class. Basically:

 Function<Class<T>, T> fun;

I can define this function within a method but when trying to put this in a member variable, the compiler complains because the type T is unknown.

So, T is not specific to the enclosing object. It might differ from call to call. What is the correct syntax to define such a function on class level?

EDIT

I would like to clarify. I have class A

public class A {
  public <T> T get(Class<T> clazz) {...}
}

Now, I want to hand a pointer to that function to class B like this:

public class B {
  <T> Function<Class<T>, T> fun;
  
  public <T> T get(Class<T> clazz) {
    return fun.apply(clazz);
  }
}

However, the Syntax for <T> Function<Class<T>, T> fun is incorrect. Is there a way to keep the information, that fun will always retain the type T?

My current solution is

public class B {
  Function<Class<?>, ?> fun;

  public <T> void setFun(Function<Class<T>, T> fun) {
    this.fun = fun;
  }

  public <T> T get(Class<T> clazz) {
    return (T) fun.apply(clazz);
  }
}

This works (and is obviously correct via invariant) but kinda ugly because of the required cast.

like image 833
Jonathan Avatar asked Oct 15 '22 00:10

Jonathan


1 Answers

In Java (and JVM) values are not polymorphic, methods are.

So correct is to define it with a method

<T> Function<Class<T>, T> fun();

Polymorphic values in Java


Regarding EDIT.

Now, I want to hand a pointer to that function to class B like this:

public class B {
  <T> Function<Class<T>, T> fun;
 
  public <T> T get(Class<T> clazz) {
    return fun.apply(clazz);
  }
}

Once again, a value (including a field) can't be polymorphic, method can.

  • So you can make fun a method

     public abstract class B {
        abstract <T> Function<Class<T>, T> fun();
    
        public <T> T get(Class<T> clazz) {
            return this.<T>fun().apply(clazz);
        }
     }
    

    You can't write setter like setFun. Its signature should be something like

     public void setFun(<T> Function<Class<T>, T> fun); // pseudocode
    

    rather than

     public <T> void setFun(Function<Class<T>, T> fun);
    

    <T> Function<Class<T>, T> is called rank-N type and it's absent in Java

    What is the purpose of Rank2Types?

    https://wiki.haskell.org/Rank-N_types

  • Alternatively, you can wrap polymorphic fun with a class (interface)

    public interface PolyFunction {
        <T> T apply(Class<T> clazz);
    }
    
    public class B {
        PolyFunction fun;
    
        public void setFun(PolyFunction fun) {
            this.fun = fun;
        }
    
        public <T> T get(Class<T> clazz) {
            return fun.apply(clazz);
        }
    }
    

    PolyFunction looks like your A so maybe you want

    public class B {
        A a;
    
        public void setA(A a) {
            this.a = a;
        }
    
        public <T> T get(Class<T> clazz) {
            return a.get(clazz);
        }
    }
    
like image 55
Dmytro Mitin Avatar answered Oct 31 '22 10:10

Dmytro Mitin