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

Option to omit toString generation #50

Open
drewhamilton opened this issue Apr 28, 2021 · 1 comment · May be fixed by #231
Open

Option to omit toString generation #50

drewhamilton opened this issue Apr 28, 2021 · 1 comment · May be fixed by #231
Labels
enhancement New feature or request

Comments

@drewhamilton
Copy link
Owner

drewhamilton commented Apr 28, 2021

Generated toString implementations add to the string pool, and can't be removed by optimizers like R8 due to the general widely-used nature of toString. For this reason it is desirable in some contexts to skip toString—only generate equals and hashCode—on internal value types. It would be nice if Poko had a way to do this for some, but not all, classes in a module/project.

In the meantime, it's possible to achieve the desired behavior manually:

@Poko class Thing(
    val property: OtherThing,
) {
    override fun toString(): String = super.toString()
}
@drewhamilton drewhamilton added the enhancement New feature or request label Apr 28, 2021
drewhamilton pushed a commit that referenced this issue Aug 14, 2023
An integer is its own hashCode, and the function is documented to simply return the input on the JVM. For JS and native the behavior is the same: https://github.com/JetBrains/kotlin/blob/1.9.0/kotlin-native/runtime/src/main/kotlin/kotlin/Primitives.kt#L1353.

Saves at least 3 bytes per property within the function bytecode, not counting any effects on things like the constant pool (for JVM).

Before:

    public int hashCode();
      Code:
         0: aload_0
         1: getfield      #23                 // Field int:I
         4: invokestatic  #50                 // Method java/lang/Integer.hashCode:(I)I
         7: istore_1
         8: iload_1
         9: bipush        31
        11: imul
         ⋮
        46: ireturn

After:

    public int hashCode();
      Code:
         0: aload_0
         1: getfield      #23                 // Field int:I
         4: istore_1
         5: iload_1
         6: bipush        31
         8: imul
         ⋮
        43: ireturn
@lexa-diky lexa-diky linked a pull request Sep 6, 2023 that will close this issue
@drewhamilton
Copy link
Owner Author

drewhamilton commented Sep 6, 2023

There are a few API design options that come to mind. These all interact with #67's design in some way, so probably both designs need to be fleshed out at the same time.

  1. Add a separate class-level annotation: @DisableToStringGeneration @Poko class Blah(...). This is the simplest to implement. But it's not as concise as other options. It doesn't scale well if we want other class-level behavior customizations. Doesn't play well with one Cache computed hashCode and toString for deeply immutable types #67 proposal, which is to add @Memoized to each function declaration—what should happen if this annotation is used but @Memoized is also added to toString?

  2. Add a property to the existing @Poko annotation: @Poko(generateToString = false). More concise and scales better than (1), but maybe still not super well. Doesn't play well with the same Cache computed hashCode and toString for deeply immutable types #67 approach that (1) doesn't play well with—what should happen if generateToString is false but @Memoized is also added to toString?

  3. Add a property for each of the three generated functions to @Poko, and use an enum to define each value. This seems like it would scale better. But it feels weird to sort of write functions inside an annotation. And it's not clear what should happen if someone explicitly chooses one of these options but manually overrides the corresponding function at the same time.

@Poko(
    equals = INCLUDED|EXCLUDED|MEMOIZED,
    hashCode = INCLUDED|EXCLUDED|MEMOIZED,
    toString = INCLUDED|EXCLUDED|MEMOIZED,
)
  1. Stick with the workaround listed above. This may be the best option if all the others require compromises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant