Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate an empty class for the non-generated classes #642

Open
HosseinYousefi opened this issue May 9, 2023 · 6 comments
Open

Generate an empty class for the non-generated classes #642

HosseinYousefi opened this issue May 9, 2023 · 6 comments

Comments

@HosseinYousefi
Copy link
Member

HosseinYousefi commented May 9, 2023

Update:
As #642 mentions, it's good to generate empty classes with defined supertypes for the ungenerated classes. This approach takes care of both of the problems while giving access to the supertype methods.

Currently if a getter or a method returns ArrayList, and we don't have java.util.ArrayList generated somewhere, we replace it with JObject.

JObject getList() {
 // ...
}

We could instead replace it with the first available superclass, in this case if java.util.List is available, we could replace it with JList:

JList getList() {
  // ...
}

This is useful, since you still can do all the list operations even if you don't have access to ArrayList's specific methods.

It's not as useful to convert an java.util.ArrayList inside arguments to java.util.List, since you'd still have to pass an ArrayList and not a List to the method. Keeping JObject as the replacement here better signals the fact that this argument might not be generated, prompting the developer to actually generate the class instead of assuming that the required argument is of a super type. We could even consider having a NonGeneratedJavaClass which acts the same as a JObject but really signals this fact.

@dcharkes
Copy link
Collaborator

dcharkes commented May 9, 2023

How intertwined is Java code? E.g. What happens if we just generate the class because it occurs in a method signature of a class that we generate (and we didn't exclude that method.) Does that in Java mean we automatically generate the world?

One question is, what is the best place to break that boundary? Should we consider generating that class, but excluding all methods in it so that we just have the transitively referenced type hierarchy? With a comment on the "empty" class on how to add that class to the jnigen.yaml? (This would be somewhat similar to what we do in FFIgen where if a type is only referenced in a pointer, we generate an Opaque which has no members instead of a Struct with all its members.)

@HosseinYousefi
Copy link
Member Author

How intertwined is Java code? E.g. What happens if we just generate the class because it occurs in a method signature of a class that we generate (and we didn't exclude that method.) Does that in Java mean we automatically generate the world?

We don't have to keep generating of course, maybe we generate A and we need to call A.f(B b) and maybe B also needs C to be constructed. But if we never use some C.f(D d) then it's not really necessary to generate D. We can let it be JObject as we never use it.

Sometimes a parameter is optional, or we always choose to pass null to it, so it doesn't make sense to generate the full class for it.

Another reason why we might still want to have the method is when passing objects through a pipeline and not caring about the intermediate results. Say f(A a) returns a B and g(B b) returns a C and we only want to do g(f(a)) and never f(a) directly. In this case generating B is not really useful.

Of course the problem with all of that is no type safety and relying on the programmer to know which types are compatible. So one could argue even though we don't explicitly need B, it's still useful to generate it for a better type safety.

@dcharkes
Copy link
Collaborator

dcharkes commented May 9, 2023

So I'm thinking what if we generate empty classes (just the class, the type-class, and it's super types), but no methods for every class that we encounter in the methods that are in the classes that we have specified to generate. Would that give us a type-safe way of dealing with these? Or would that already explode in the amount of generated code?

@HosseinYousefi
Copy link
Member Author

I think it would be OK tbh. We only go one level deep when we generate empty classes anyways.

@HosseinYousefi HosseinYousefi changed the title Generate the first available superclass for returned objects Generate an empty class for the non-generated classes May 9, 2023
@mahesh-hegde
Copy link
Contributor

Or would that already explode in the amount of generated code?

Shouldn't be much in terms of generated code. But that can add some noise to auto-completion suggestions. Has to be checked in a real use case.

you can also add just another config flag (sigh) in case that noise is significant.

empty_classes:
  - java.util

@dcharkes
Copy link
Collaborator

But that can add some noise to auto-completion suggestions

That has not been my experience with the Opaques generated for Pointer<T extends Opaque> params in FFIgen. But it could of course be true that Java code is different from C code.

Let's try without a flag, to see if the noise is acceptable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

No branches or pull requests

3 participants