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

[Kotlin] Generate open classes and methods #1815

Merged
merged 3 commits into from
Nov 8, 2023

Conversation

jmartinesp
Copy link
Contributor

This PR is an alternative implementation of #1782 , with the 1st approach @bendk proposed here:

We could make the concrete type open. It's slightly risky because if you don't have an actual handle to a Rust object, then calling a UniFFI function will fail. But I would be okay with saying that users accept that risk if they extend the generated class. For your use case of only creating the objects if the native library isn't available, it seems like it should work fine.

The implementation changes are:

  • FFIObject.pointer is now nullable. I know it's not great, but it's necessary as far as I can tell and I haven't seen any issues with it so far.
  • FFIObject now has an alternate constructor(noPointer: NoPointer). I tried using an empty constructor or one with pointer: Pointer? as the only parameter, but it clashed with the code in generated classes.
  • FFIObject.freeRustArcPtr implementation in the different classes now does a null check before trying to free the pointer, so you don't need to override it in the fakes, and methods using callWithPointer will unwrap the nullable value and throw a NullPointerException if it doesn't exist.
  • I removed the interfaces for concrete types because they don't seem to have any use, since you can't implement some FooInterface and just pass it to a fn bar(foo: Foo) function without a ClassCastException, and the open class can now act as a kind of interface (again, I might be wrong about this, they could be restored). I did keep the interface for the trait interfaces and their impls.

I added a few tests displaying how these open classes can be extended, used and not used in a real project.

I feel like this approach isn't as correct as the one in #1782 where you'd be forced to provide an alternative implementation for the interfaces that doesn't crash, but it's way simpler to maintain and the drawbacks I see as a lib user aren't that bad.

@jmartinesp jmartinesp requested a review from a team as a code owner October 28, 2023 08:27
@jmartinesp jmartinesp requested review from tarikeshaq and removed request for a team October 28, 2023 08:27
@jmartinesp
Copy link
Contributor Author

Hmm... I see this could clash with #1808. Maybe the UniffiHandleWrapper could be an enum with Some/None cases instead of the nullable Pointer used here.

@bendk
Copy link
Contributor

bendk commented Oct 28, 2023

Hmm... I see this could clash with #1808. Maybe the UniffiHandleWrapper could be an enum with Some/None cases instead of the nullable Pointer used here.

I haven't checked this code, but you can use -1 to represent a null handle. In general, the negative numbers are reserved for special cases.

@arg0d arg0d mentioned this pull request Oct 31, 2023
@tarikeshaq tarikeshaq requested review from bendk and removed request for tarikeshaq November 7, 2023 16:34
Copy link
Contributor

@bendk bendk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great overall, but can you add back in the interface definition? I think that's still useful.

* @param noPointer Placeholder value so we can have a constructor separate from the default empty one that may be
* implemented for classes extending [FFIObject].
*/
constructor(noPointer: NoPointer): super(noPointer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great docstring and I like the use of the singleton object to differentiate this from the regular constructor.

- Also make their methods open.
- Make the `Pointer` in `FfiObject` optional.
- Add a `constructor(noPointer: NoPointer)` to create a FFiObject with no pointer for fakes.
- Remove redundant interfaces since they can be implemented, but not used in any way.
- Add tests for fakes.
@jmartinesp jmartinesp requested a review from bendk November 7, 2023 21:41
Copy link
Contributor

@bendk bendk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks for the contribution!

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

Successfully merging this pull request may close these issues.

2 participants