Higher-kinded generics in Java - java

Suppose I have the following class:
public class FixExpr {
Expr<FixExpr> in;
}
Now I want to introduce a generic argument, abstracting over the use of Expr:
public class Fix<F> {
F<Fix<F>> in;
}
But Eclipse doesn't like this:
The type F is not generic; it cannot be parametrized with arguments <Fix<F>>
Is this possible at all or have I overlooked something that causes this specific instance to break?
Some background information: in Haskell this is a common way to write generic functions; I'm trying to port this to Java. The type argument F in the example above has kind * -> * instead of the usual kind *. In Haskell it looks like this:
newtype Fix f = In { out :: f (Fix f) }

I think what you're trying to do is simply not supported by Java generics. The simpler case of
public class Foo<T> {
public T<String> bar() { return null; }
}
also does not compile using javac.
Since Java does not know at compile-time what T is, it can't guarantee that T<String> is at all meaningful. For example if you created a Foo<BufferedImage>, bar would have the signature
public BufferedImage<String> bar()
which is nonsensical. Since there is no mechanism to force you to only instantiate Foos with generic Ts, it refuses to compile.

Maybe you can try Scala, which is a functional language running on JVM, that supports higher-kinded generics.
[ EDIT by Rahul G ]
Here's how your particular example roughly translates to Scala:
trait Expr[+A]
trait FixExpr {
val in: Expr[FixExpr]
}
trait Fix[F[_]] {
val in: F[Fix[F]]
}

In order to pass a type parameter, the type definition has to declare that it accepts one (it has to be generic). Apparently, your F is not a generic type.
UPDATE: The line
F<Fix<F>> in;
declares a variable of type F which accepts a type parameter, the value of which is Fix, which itself accepts a type parameter, the value of which is F. F isn't even defined in your example. I think you may want
Fix<F> in;
That will give you a variable of type Fix (the type you did define in your example) to which you are passing a type parameter with value F. Since Fix is defined to accept a type parameter, this works.
UPDATE 2: Reread your title, and now I think you might be trying to do something similar to the approach presented in "Towards Equal Rights for Higher-Kinded Types" (PDF alert). If so, Java doesn't support that, but you might try Scala.

Still, there are ways to encode higer-kinded generics in Java. Please, have a look at higher-kinded-java project.
Using this as a library, you can modify your code like this:
public class Fix<F extends Type.Constructor> {
Type.App<F, Fix<F>> in;
}
You should probably add an #GenerateTypeConstructor annotation to your Expr class
#GenerateTypeConstructor
public class Expr<S> {
// ...
}
This annotation generates ExprTypeConstructor class.
Now you can process your Fix of Expr like this:
class Main {
void run() {
runWithTyConstr(ExprTypeConstructor.get);
}
<E extends Type.Constructor> void runWithTyConstr(ExprTypeConstructor.Is<E> tyConstrKnowledge) {
Expr<Fix<E>> one = Expr.lit(1);
Expr<Fix<E>> two = Expr.lit(2);
// convertToTypeApp method is generated by annotation processor
Type.App<E, Fix<E>> oneAsTyApp = tyConstrKnowledge.convertToTypeApp(one);
Type.App<E, Fix<E>> twoAsTyApp = tyConstrKnowledge.convertToTypeApp(two);
Fix<E> oneFix = new Fix<>(oneAsTyApp);
Fix<E> twoFix = new Fix<>(twoAsTyApp);
Expr<Fix<E>> addition = Expr.add(oneFix, twoFix);
process(addition, tyConstrKnowledge);
}
<E extends Type.Constructor> void process(
Fix<E> fixedPoint,
ExprTypeConstructor.Is<E> tyConstrKnowledge) {
Type.App<E, Fix<E>> inTyApp = fixedPoint.getIn();
// convertToExpr method is generated by annotation processor
Expr<Fix<E>> in = tyConstrKnowledge.convertToExpr(inTyApp);
for (Fix<E> subExpr: in.getSubExpressions()) {
process(subExpr, tyConstrKnowledge);
}
}
}

It looks as if you may want something like:
public class Fix<F extends Fix<F>> {
private F in;
}
(See the Enum class, and questions about its generics.)

There is a roundabout way to encode higher kinded types in Java as pointed out by Victor. The gist of it is to introduce a type H<F, T> to encode F<T>. This can then be used to encode fixed point of functors (i.e. Haskell's Fix type):
public interface Functor<F, T> {
<R> H<F, R> map(Function<T, R> f);
}
public static record Fix<F extends H<F, T> & Functor<F, T>, T>(F f) {
public Functor<F, Fix<F, T>> unfix() {
return (Functor<F, Fix<F, T>>) f;
}
}
From here you can go on and implement catamorphisms over initial algebras:
public interface Algebra<F, T> extends Function<H<F, T>, T> {}
public static <F extends H<F, T> & Functor<F, T>, T> Function<Fix<F, T>, T> cata(Algebra<F, T> alg) {
return fix -> alg.apply(fix.unfix().map(cata(alg)));
}
See my GitHub repo for working code including some example algebras. (Note, IDE's like IntelliJ struggle with the code although it compiles and runs just fine with Java 15).

Related

java generics - "extends" keyword -> not supporting add elements

I am stuck with a strange problem due to java generics "extend" keyword. I have developed a generic method to get the elements from a method as generic as possible.
When I use <? extends X>, I am not able to add any elements to it.
In my case I am using the generic template to restrict the arguments provided by the user and providing the return type ac.
class Root{
}
class Sub_1 extends Root{
}
class Sub_2 extends Root{
}
public static <T extends Root> List<T> getSubElements(Class<T> targetClass){
List<T> ls=new ArrayList<>();
if(targetClass.getSimpleName().equals("Sub_1")){
Sub_1 sub_1 = new Sub_1();
ls.add(sub_1);
}else if(targetClass.getSimpleName().equals("Sub_2")){
Sub_2 sub_2=new Sub_2();
ls.add(sub_2);
}
return ls;
}
In the above case, I am getting compilation error when I add elements to the list.
ls.add(sub_1);
ls.add(sub_2);
It looks quite challenging now to solve this issue.. I will be happy if someone can provide some hints here.
Thanks!!
You can do this in a type-safe way, without using reflection, by having the caller pass in a Supplier of the desired type instead of the Class of that type. The getSubElement code then simply calls the supplier to get the right instance:
static <T extends Root> List<T> getSubElements(Supplier<T> s) {
List<T> ls = new ArrayList<>();
ls.add(s.get());
return ls;
}
The caller needs to provide a way to create an instance of its desired subclass. This might be using a constructor reference, or it could be a reference to a static factory method. If the class hierarchy is like so:
public class Root { }
public class Sub1 extends Root {
public Sub1() { ... }
}
public class Sub2 extends Root {
public static Sub2 instance() { ... }
}
Then callers could write code like the following:
List<Sub1> list1 = getSubElements(Sub1::new);
List<Sub2> list2 = getSubElements(Sub2::instance);
If you can accept any class derived from Root, and all have a default constructor...
public static <T extends Root> List<T> getSubElements(Class<T> targetClass) throws ReflectiveOperationException {
List<T> ls = new ArrayList<>();
T t = targetClass.getDeclaredConstructor().newInstance();
ls.add(t);
return ls;
}
... or try/catch exception locally.
To sum things up, here is a verified working implementation, checked using an online java compiler:
import java.util.*;
class Root{
}
class Sub_1 extends Root{
}
class Sub_2 extends Root{
}
public class Bla {
public static <T extends Root> T factoryMethod(Class<T> targetClass) throws Exception{
if (Sub_1.class ==(targetClass)) {
return (T) (new Sub_1());
}
else if (Sub_2.class == (targetClass)) {
return (T) (new Sub_2());
}
else {
throw new Exception("Unsupported class type");
}
}
public static List<Root> getSubElements() throws Exception{
List<Root> ls=new ArrayList<>();
ls.add(factoryMethod(Sub_1.class));
ls.add(factoryMethod(Sub_2.class));
return ls;
}
public static void main(String[] args) {
try {
List<Root> root = getSubElements();
System.out.println(root);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I would rather say the answer depends on boundary conditions. we can write code to get the necessary functionality but they may/may not adhere to various boundaries conditions like performance, security, integrity ,.. etc
e.g:
The following code
**T newInstance = targetClass.newInstance();**
**list.add(newInstance);**
can also achieve necessary functionality but may/may not adhere to performance boundary, coz any call to reflective methods checks for security access.
The solution with Supplier posted above also achieves a similar functionality , but it may not adhere to security boundary as a malicious supplier can supply values which can lead to buffer overflow or DOS attacks.
(if you really want to to try it out you can create a static supplier and initialize with self.. you will get an stack overflow. java generics book also provide a similar security related example which you can refer). The problem i see lies in the java open sub-typing in the current scenario .
There are other solutions also to achieve required functionality ( with slight modification to way of subtyping created) which may/may not adhere to these boundary conditions. The problem i see is due to open sub-typing system and makes it verbose and difficult for developers to write code adhering to all boundary conditions.
The solution also depends completely up on your model structure whether you have created a sub-typing coz of your data or or based on behavior , which might not reflect in this short example.
you can refer Java Generics Book by Philiph Wadler for more details on working with generics which i would recommend. it also gives an important aspect of writing code in a secure way. On an interesting note you can refer to project amber (java 11 or later) regarding Data Classes for java which tries to address some of these problems.

Java generics - Does Java need support for locally defined types?

I am hoping to reach the Java generics experts here. Let's say you have some typed class:
public interface SomeClass<T> {
void doSomething(final T t);
}
There is also a function which gets you an instance of T given an instance of SomeClass<T>:
public static class Retriever {
public <T> T get(final SomeClass<T> c) {
return null; // actual implementation left out
}
}
Now let's say you have a collection of SomeClass<?> and a retriever:
final List<SomeClass<?>> myClasses = null; // actual implementation left out
final Retriever myRetriever = null; // actual implementation left out
We are not able to do the following:
for (final SomeClass<?> myClass : myClasses) {
myClass.doSomething(myRetriever.get(myClass));
}
Now my question: does Java need support to be able to locally define a type? Something like:
<T> for (final SomeClass<T> myClass : myClasses) {
myClass.doSomething(myRetriever.get(myClass));
}
Here, the type T is scoped to the for-loop. We are defining T to get rid of the wildcard ?. That's it. The introduction of T should enable us to write the desired for loop as expressed above.
FWIW, the following code is a workaround. We are introducing a function, solely for the conversion of ? to T.
for (final SomeClass<?> myClass : myClasses) {
workAround(myRetriever, myClass);
}
public static <T> void workAround(final Retriever myRetriever, final SomeClass<T> myClass) {
myClass.doSomething(myRetriever.get(myClass));
}
A locally defined user type might be a more elegant solution?
Now my question: does Java need support to be able to locally define a type?
No. The minimal scope of a type-parameter is the method, i.e. in order to have the type T available for your for loop, you will have to either defined the enclosing method a generic or the enclosing class. For example:
<T> void method(List<SomeClass<T> myClasses) {
for (final SomeClass<T> myClass : myClasses) {
myClass.doSomething(myRetriever.get(myClass));
}
}

Instantiate generified class after loading from repository

When writing a type handler for a repository (such as a web service or a database), I need to instantiate the type after the value is loaded from the repository.
Let's say I get a String value from the repository and there is a constructor with one String argument that I can use. If the return type has a type parameter, what else can I do besides instantiating the raw type? It seems raw types exist only for compatibility with legacy code so I would prefer not to use them.
Normally ? can be used as type parameter (if you know the type will be correct at runtime), but not in this case because you can't instantiate classes with wildcards as type parameter.
EDIT: some example code:
Let's say I have a PrimaryKey class like this:
public class PrimaryKey<R extends RepositoryObject<R>> {
private String value;
public PrimaryKey(String value) {
this.value = value;
}
}
And a set of classes that extend RepositoryObject, which is defined like this:
public class RepositoryObject<R extends RepositoryObject<R>> {
private PrimaryKey<R> pk;
public RepositoryObject(PrimaryKey<R> pk) {
this.pk = pk;
}
PrimaryKey<R> getPrimaryKey() {
return pk;
}
}
Example of a subclass:
public class User extends RepositoryObject<User> {
public User(PrimaryKey<User> userId) {
super(userId);
}
}
Now the type handling method for class PrimaryKey will look something like this:
public PrimaryKey<?> getValue(String stringValue) {
return new PrimaryKey<>(stringValue);
}
But this results in a compiler error (in the Maven build, not in Eclipse IDE strangely enough) even though I'm using the diamond operator instead of when instantiating. Maybe for some reason type inference doesn't work well because of the recursion in the type parameters.
In Java 7 you can typically use the diamond operator to get around this limitation:
Container<?> c = new Container<>(arg);
Otherwise you can use a helper factory method:
<T> Container<T> makeContainer(String arg) {
return new Container<T>(arg);
}
...
Container<?> c = makeContainer(arg);
EDIT:
Following your update, I can see you're using a recursive type parameter <R extends RepositoryObject<R>>. This compile error is due to limitations of javac when it comes to wildcard capture and recursive type parameters. See this related post for example: Java CRTP and Wildcards: Code compiles in Eclipse but not `javac`
Unfortunately, using a raw type is necessary as a workaround, but it can be hidden as an implementation detail:
public PrimaryKey<?> getValue(String stringValue) {
#SuppressWarnings("rawtypes") //a raw type is necessary to placate javac
final PrimaryKey<?> pk = new PrimaryKey(stringValue);
return pk;
}
class SomeBogusClass extends RepositoryObject<SomeBogusClass> { }
return new PrimaryKey<SomeBogusClass>(stringValue);
seriously, you can put anything there that satisfies the bounds, even some bogus class that has nothing to do with your code.

.Net equivalent for Java typed Class<>?

I'm a .NET guy, so let me first assert my understanding of a few Java concepts - correct me if I'm wrong.
Java Generics support the concept of bounded wildcards:
class GenericClass< ? extends IInterface> { ... }
...which is similar to the .NET where restriction:
class GenericClass<T> where T: IInterface { ... }
Java's Class class describes a type, and is roughly equivalent to .NET Type class
So far, so good. But I can't find a close enough equivalence to the Java genericly typed Class<T> where T is a bounded wildcard. This basically imposes a restriction on the types that the Class represents.
Let me give an example in Java.
String custSortclassName = GetClassName(); //only known at runtime,
// e.g. it can come from a config file
Class<? extends IExternalSort> customClass
= Class.forName("MyExternalSort")
.asSubclass(IExternalSort.class); //this checks for correctness
IExternalSort impl = customClass.newInstance(); //look ma', no casting!
The closest I could get in .NET is something like this:
String custSortclassName = GetClassName(); //only known at runtime,
// e.g. it can come from a config file
Assembly assy = GetAssembly(); //unimportant
Type customClass = assy.GetType(custSortclassName);
if(!customClass.IsSubclassOf(typeof(IExternalSort))){
throw new InvalidOperationException(...);
}
IExternalSort impl = (IExternalSort)Activator.CreateInstance(customClass);
The Java version looks cleaner to me.
Is there a way to improve the .NET counterpart ?
Using extension methods & a custom wrapper class for System.Type, you can get pretty close to the Java syntax.
NOTE: Type.IsSubclassOf cannot be used to test if a type implements an interface - see the linked documentation on MSDN. One can use Type.IsAssignableFrom instead - see the code below.
using System;
class Type<T>
{
readonly Type type;
public Type(Type type)
{
// Check for the subtyping relation
if (!typeof(T).IsAssignableFrom(type))
throw new ArgumentException("The passed type must be a subtype of " + typeof(T).Name, "type");
this.type = type;
}
public Type UnderlyingType
{
get { return this.type; }
}
}
static class TypeExtensions
{
public static Type<T> AsSubclass<T>(this System.Type type)
{
return new Type<T>(type);
}
}
// This class can be expanded if needed
static class TypeWrapperExtensions
{
public static T CreateInstance<T>(this Type<T> type)
{
return (T)Activator.CreateInstance(type.UnderlyingType);
}
}
Further improvements using interface variance
(Should only be used in production code after the performance has been evaluated. Could be improved by using a (concurrent!) cache dictionary ConcurrentDictionary<System.Type, IType<object>)
Using Covariant type parameters, a feature introduced with C# 4.0, and an additional type interface IType<out T>, which Type<T> implements, one could make things like the following possible:
// IExternalSortExtended is a fictional interface derived from IExternalSort
IType<IExternalSortExtended> extendedSort = ...
IType<IExternalSort> externalSort = extendedSort; // No casting here, too.
One could even do:
using System;
interface IType<out T>
{
Type UnderlyingType { get; }
}
static class TypeExtensions
{
private class Type<T> : IType<T>
{
public Type UnderlyingType
{
get { return typeof(T); }
}
}
public static IType<T> AsSubclass<T>(this System.Type type)
{
return (IType<T>)Activator.CreateInstance(
typeof(Type<>).MakeGenericType(type)
);
}
}
static class TypeWrapperExtensions
{
public static T CreateInstance<T>(this IType<T> type)
{
return (T)Activator.CreateInstance(type.UnderlyingType);
}
}
So that one can (explicitly) cast between unrelated interfaces InterfaceA and InterfaceB like:
var x = typeof(ConcreteAB).AsSubclass<InterfaceA>();
var y = (IType<InterfaceB>)x;
but that kinda defeats the purpose of the exercise.
C# generics is declaration-site variance, the variance of a type parameter is fixed.
Java is use-site variance, so once we have a declaration List<E>, we can use it 3 ways
List<Number> // invariant, read/write
List<+Number> // covariant, read only
List<-NUmber> // contravariant, write only
There are pros and cons to both approaches. The use-site approach is apparently more powerful, though it gained the reputation as being too difficult to programmers. I think it is actually pretty easy to grasp
List<Integer> integers = ...;
List<+Number> numbers = integers; // covariant
Unfortunately, Java invented an absolutely hideous syntax,
List<? extends Number> // i.e. List<+Number>
once your code has several of these it becomes really ugly. You have to learn to get over it.
Now, in the declaration-site camp, how do we achieve 3 variances on the same class? By having more types - a ReadOnlyList<out E>, a WriteOnlyList<in E>, and a List<E> extending both. This is not too bad, and one might say it's a better design. But it may become ugly if there are more type parameters. And if the designer of a class did not anticipate it being used variantly, the users of the class have no way to use it variantly.
You can get a slightly prettier version using the "as" operator:
String custSortclassName = GetClassName();
Assembly assy = GetAssembly();
Type customClass = assy.GetType(custSortclassName);
IExternalSort impl = Activator.CreateInstance(customClass) as IExternalSort;
if(impl==null) throw new InvalidOperationException(...);
But here I'm creating the instance before checking its type, which may be an issue for you.
You can try writing an extension method like the following:
static class TypeExtension
{
public static I NewInstanceOf<I>(this Type t)
where I: class
{
I instance = Activator.CreateInstance(t) as I;
if (instance == null)
throw new InvalidOperationException();
return instance;
}
}
Which can then be used in the following manner:
String custSortclassName = GetClassName(); //only known at runtime,
// e.g. it can come from a config file
Assembly assy = GetAssembly();
Type customClass = assy.GetType(custSortclassName);
IExternalSort impl = customClass.NewInstanceOf<IExternalSort>();

Java generic parameter itself using generics?

I'm trying to figure out how to structure a program using Java's generics, and wondering if I am doing something fundamentally wrong or just missing a simple bug in my code.
Say I have a generic class:
public interface Handler<T>{
public void process(T t);
}
Another generic class takes Handler as a generic parameter (pseudo code):
public interface Processor<S extends Handler<T>>{ //<== Error: cannot find symbol 'T'
public void addHandler(S u);
public void process(T t);
}
Abstract implementation providing boiler-plate implementations
public abstract class ProcessorImpl<.....> implements Processor<.....>{
...
}
Think of a processor as an object that dispatches requests to process data to any number of handlers. Specific instances can be variations of process pipelines, intercepting filters, event systems, etc.
I'd like to be able to use it like the following:
Handler<String> myHandler1 = new HandlerImpl<String>();
Handler<String> myHandler2 = new HandlerImpl<String>();
Handler<Integer> myHandler3 = new HandlerImpl<Integer>();
Processor<Handler<String>> proc = ProcessorImpl<Handler<String>>();
proc.addHandler(myHandler1);
proc.addhandler(myHandler2);
proc.addhandler(myHandler3);//this should be an error!
I can't get it to work. On paper it looks like it should be trivial, any ideas?
Thanks
So each type parameter is only defined within the class, thus T isn't defined or available in Processor class.
You probably want to have Processor be:
public interface Processor<T>{
public void addHandler(Handler<? super T> u);
public void process(T t);
}
Here you are declaring a Processor that can only handle events/input of a particular type, e.g. String, Integer, etc. So the following statement will be valid:
Processor<String> proc = ...
proc.addHandler(new Handler<String>()); // valid
proc.addHandler(new Handler<Object>()); // valid, as Strings are Objects too
proc.addHandler(new Handler<Integer>()); // invalid, not a String handler
proc.process("good"); // valid
proc.process(1); // invalid, not a String
If Processor is intended to handle types at runtime and makes a dynamic dispatch based on the appropriate runtime type, then you can declare proc (in the last example) as Processor<?>. Then all the statements are valid.
These changes should work:
public interface Processor<T, S extends Handler<T>>
and
class ProcessorImpl<T, S extends Handler<T>>
implements Processor<T, S>
and
Processor<String, Handler<String>> proc = new ProcessorImpl<String, Handler<String>>();
It shouldn't work, as your T=String and handlers of integers are not allowed.
At compile time, your class will have method process(String t) and not process(Integer t).

Categories