-
Notifications
You must be signed in to change notification settings - Fork 586
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
Add inherited option to @Virtual #660
Conversation
That seems fine, but the word "inherit" means the other way around, such that, for example, a user might think they need to provide |
What about "inheritable" ? |
But it's not "inheritance" as understood for classes, so this is confusing. What about something like Info.virtualize().skipSubclasses() ? It's consistent with others like skipDefaults. |
I have no preference between skipSubclasses or inheritable. |
Or something like |
I don't think there's anything else than virtualize that modifies the behavior in subclasses, but if there were, we could reuse that flag, so that's fine for other potential future use cases. |
It doesn't sound rigorous to me. What if I want to skipSubclasses for virtualization but not for this future behavior ? Create 2 Info ? But in most places in the source we check the first Info attached to a cppName. Ok, this has little chance to happen, and the whole Info system may well be remastered in JavaCPP 2, but well... I think adding an optional parameter to |
I'm starting to feel like you're trying to add unnecessary complexity. If the only use case you have for this is String[] virtuals = {"clone", "train", "is_training", "to", "zero_grad", "save", "load", "pretty_print", "is_serializable",
"_forward_has_default_args", "_forward_num_required_args", "_forward_populate_default_args"};
for (int i = 0; i < virtuals.length; i++) {
virtuals[i] = "torch::nn::Module::" + virtuals[i];
}
infoMap.put(new Info(virtuals).annotations("@Virtual")); Why isn't that satisfactory? |
Because Yes, the current need is for Pytorch, but I try to generalize the solution so that it can benefit to other presets. The typical use case is explained in original post above. And the needed modifications in JavaCPP are quite small. |
If those functions need their signatures adjusted, we can make Info.virtualize() work for functions too. Anything missing from that? |
A virtualized function will be "inherited". This inheritance mechanism is in Generator and works at the level of the function. |
I see, what we need to modify really is just the String[] virtuals = {"clone", "train", "is_training", "to", "zero_grad", "save", "load", "pretty_print", "is_serializable",
"_forward_has_default_args", "_forward_num_required_args", "_forward_populate_default_args"};
for (int i = 0; i < virtuals.length; i++) {
virtuals[i] = "torch::nn::Module::" + virtuals[i];
}
infoMap.put(new Info("torch::nn::Module").virtualize()).put(new Info(virtuals).annotations("@Virtual(subclasses=false)")); And then in Parser.java, check whether |
That should work, but I wonder why you don't want to add a parameter to Info.virtualize to back up the subclasses option of |
Right, this is the first I hear about needing something like that. |
virtualize can target functions. Rename @virtual parameter
I added a line to allow virtualize to target functions.
and could be useful in other cases. |
Good to merge ? |
@@ -2357,8 +2357,7 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti | |||
|
|||
type = functionAfter(context, decl, dcl, type); | |||
context = new Context(context); | |||
if (info != null) context.virtualize |= info.virtualize; | |||
context.virtualize &= type.virtual; | |||
context.virtualize = (context.virtualize && type.virtual) || (info != null && info.virtualize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You changed a bit the logic here.
Now methods with info.virtualize will have context.virtualize true, even if not virtual (and trigger annotations etc...).
Not a big deal since there is no reason to add the info on a non virtual function, but the previous code seems more logical to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's intentional, and I thought that was fine, I guess...?
B is a base class with a virtual method
m
. D is a derived class.If you want to override
m
in Java, you add anew Info("B").virtualize()
, which main effect is to annotate the Java methodm
with@Virtual
. The generator then creates a proxy C++ subclass forB
, but also forD
, so that you can create Java subclass of D that overridesm
. Thus the ability to override in Java is "inherited" fromB
byD
.This PR adds the option to prevent this inheritance.
The use of the proxy class that polls the JVM each time the C++
m
is called has a cost that may not be negligible.So preventing this inheritance is useful for libraries that provide a parent virtual class, that can be subclassed, and concrete subclasses that are not meant to be subclassed.
This is the case of Pytorch with the
Module
class, usually subclassed by users, and numerous implementations for each layer type.If Module is virtualized and the inheritance prevented with this PR, Pytorch JNI is 30986347 bytes.
If Module is virtualized with master, Pytorch JNI is 44111566 bytes (and doesn't compile, for an obscure template error I didn't dig further).
The PR adds an Info for preventing the inheritance and nothing changes in parsed file if this new Info is not set.