Skip to content

[jnigen] Don't break method names #1529

Open

Description

@HosseinYousefi

Let's say that we have two methods void foo(float a) and void foo(double a). JNIgen generates these as void foo(double a) and void foo1(double a), the user can go ahead and use these methods as intended – using the first one for floats and the second one for doubles.

Now say an update of this code, swaps the order of the methods so now foo needs to be run on doubles and foo1 on floats. There will be no compilation error and the code fails in mysterious ways.

Once #746 lands, we can use the same generated yaml/json to see what the mappings signatures were before the regeneration and warn if the naming changes.

@liamappelbe Something to keep in mind for ffigen as well.

Activity

  1. removed their assignment
    on Sep 6, 2024
  2. dcharkes commented on Sep 10, 2024

    @dcharkes
    Collaborator

    An alternative would be to make the generator "remember" the naming choices it made before and bootstrap from that naming choice when generating dependent code or code for updated JARs - making the choice sticky and therefore much less breaking.

    We could possibly use the existing "imports" mechanism for this?

  3. HosseinYousefi commented on Sep 10, 2024

    @HosseinYousefi
    ContributorAuthor

    We could possibly use the existing "imports" mechanism for this?

    Yes. That's what I referred to in the description:

    Once #746 lands, we can use the same generated yaml/json to see what the mappings signatures were before the regeneration and warn if the naming changes.

    s/warn if the/use the same/!

  4. johnmccutchan commented on Oct 11, 2024

    @johnmccutchan

    Once #746 lands, we can use the same generated yaml/json to see what the mappings signatures were before the regeneration and warn if the naming changes.

    Warning developers is not an acceptable solution. We cannot break users of generated code just because a method was added to an existing class. Full stop.

    It sounds like when we generate the bindings, we need to generate a snapshot (json or whatever) of the mapping and when generating bindings jnigen will open that snapshot and use it ensure stable mappings.

  5. HosseinYousefi commented on Oct 11, 2024

    @HosseinYousefi
    ContributorAuthor

    Warning developers is not an acceptable solution. We cannot break users of generated code just because a method was added to an existing class. Full stop.

    Agreed.

  6. changed the title [-]Warn if regeneration renames method overloads[/-] [+][jnigen] Don't break method names[/+] on Oct 11, 2024
  7. moved this from Backlog to Todo in JNIgen trackeron Oct 23, 2024
  8. moved this from Todo to In Progress in JNIgen trackeron Dec 2, 2024
  9. dcharkes commented on Dec 5, 2024

    @dcharkes
    Collaborator

    Some notes from a discussion:

    • The info can be saved in a JSON or as annotations on the Dart source. Annotations on the Dart source has the pro that we don't have an extra file, and that we can inspect the Dart source as well. Annotations on the Dart source has the con that parsing is slower, and that we probably don't want to reverse engineer the decisions made in JNIgen from the Dart sources. Rather those decisions (such as a method was turned into a getter, or a method was renamed) should be encoded in the json/annotation.
    • The transformations feature needs to be taken into account. It can rename methods, delete them, or add new unrelated methods (which can conflict with a method added in the source later).
    • If possible, we'd like some general approach w.r.t. decision making in the implementation. E.g. previousRunOracle[uniqueResourceIdentifier]?['dart_name'] ?? uniqueRenamer(name). This should work with all kinds of decisions: renames, name conflicts, transforming getters into methods and vice versa.
    • It would be nice to align the approach with FFIgen (which also needs to deal with overrides from C, and wants to introduce transforms). @liamappelbe should do some brainstorming with @HosseinYousefi! 😄
  10. HosseinYousefi commented on Dec 9, 2024

    @HosseinYousefi
    ContributorAuthor

    Interop between the generated bindings means that if package:b imports the bindings from package:a, then we must use the correct renamings when classes in b inherit from classes in a. This is going to be in form of a json file generated alongside the dart files with all the symbols after renamings.

    On the other hand, due to the lack of method overloading and other syntactic differences between java and dart, we can have methods like foo(int) and foo(String) that will turn into foo and foo$1 in dart. If a new version of the Java library adds foo(int, int) or if one of the other methods get removed, we want the bindings to remain stable, so any code that is using them won't change. So we need a json again to keep these mappings on regeneration runs.

    We could generate the same json for both of these use cases, there is also a question of how to run transformations? Do we run them first and then do another pass to de-duplicate names using $K suffices? Or do we first de-dup and then run the transformers? In the latter case, we can have a json that is generated after de-duping for the stability purposes and another one after transformation for importing purposes and just put the responsibility on the user to avoid changes.

  11. HosseinYousefi commented on Dec 9, 2024

    @HosseinYousefi
    ContributorAuthor

    Another idea is to have a boolean is_renamed for each transformed member in the json and ignore this element for the stability as it had been transformed anyways. The responsibility is now on the user to respect semver when renaming.

    Any iteration on the transformer is treated the same way: if we rename a member that was previously automatically named, we know what we're doing, so the json is changed to use the new name and is_renamed is now true.

  12. dcharkes commented on Dec 9, 2024

    @dcharkes
    Collaborator

    Another idea is to have a boolean is_renamed for each transformed member in the json and ignore this element for the stability as it had been transformed anyways. The responsibility is now on the user to respect semver when renaming.

    I like this. For helping with semver we should encourage users to use https://pub.dev/packages/dart_apitool, instead of coming up with some JNIgen-specific solution.

    Maybe is_transformed (to cover getters<->functions etc.) or user-defined, intended, manual.

  13. moved this from In Progress to Todo in JNIgen trackeron Dec 12, 2024
  14. modified the milestones: JNI / JNIgen 2025 Q1, on Apr 8, 2025
  15. modified the milestones: , JNI / JNIgen EAP on Oct 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions