Tencent/puerts

[Unity] General Questions

Opened this issue · 5 comments

detail | 详细描述

Before diving into Puerts I'd like to see if someone can answer some questions I had:

  • Does exposing generics from C# side work? for example if I wanted to develop using generic collections from C# is that possible or do I need to use TS/JS collections?
  • Do events/delegates expose properly? If I have an event from C# side can I subscribe to it from TS side? Can I define new events on TS side?
  • Is it possible to expose a library like UniTask on the TS side? is there extra work needed to get async/await working for it?

Thank you for an awesome framework!

It partially supports C# generics, here is an example of a generic container: https://github.com/chexiongsheng/puerts_unity_demo/blob/master/projects/0_Basic_Demo/TsProj/QuickStart.mts#L57, and here is the logic for determining the scope of generic support: https://github.com/Tencent/puerts/blob/master/unity/Assets/core/upm/Runtime/Src/Default/Utils.cs#L183.
Delegates are of course supported, you can still refer to https://github.com/chexiongsheng/puerts_unity_demo/blob/master/projects/0_Basic_Demo/TsProj/QuickStart.mts#L24
Due to some limitations under il2cpp, generics are not fully supported, and UniTask may not be fully usable. I suggest writing asynchronous logic in js, using async/await can also express asynchronous logic well.

@chexiongsheng thanks for answering! regarding the following:

  • If I have APIs on C# side that I'm exposing and they return system.collection and I want to hide generics on the TS side, what's the best way to handle that kind of situation? I'd like to keep the use of generics to JS/TS and hide any C# side generics, specially collections, does the binding/static wrapper convert the types correctly if I don't bind system.collection.generic types?

  • UniTask I have C# business logic written using UniTask do I need to write wrappers for any apis to convert to regular Task for it to work in JS/TS? Is it possible to support UniTask on the C# side for async/await operations from JS?

  • Can new events/delegates be defined on JS side?

  • Puerts does not bind by default and will export APIs to JS using reflection. I understand your intention to hide, and if you want to save trouble, you can use reflection, but the performance won't be as good. If you want to prohibit the use of generics, this contradicts what you mentioned about "keep the use of generics to JS/TS".
  • Task can be converted to Promise, and then use JS's asynchronous mechanism.
  • Don't forcibly apply C# concepts to JS. JS itself does not have events/delegates, but you can use C#'s events/delegates, or you can easily implement similar things with its functions.

From your questions, I think you need to systematically learn TS/JS first.

@chexiongsheng Thank you for answering my questions! definitely there's a lot to learn specially in the context of binding.

I'll rephrase my questions to convey my intent better. For context, my need is to expose my current APIs to a scripting language and I've been evaluating Puerts for that. The scripting side's job is to interact with my/unity's APIs to build using TS/JS. I do want to use a static wrapper as opposed to reflection as performance is important for us.

  • I understand that Puerts doesn't bind by default, I will be providing which types/assemblies will be bound/statically wrapped. My question was mainly about how to handle generics that are statically wrapped on the TS side and based on your answer, il2cpp (which is the backend for my project) doesn't allow generic usage using $generic or is at least limited (though I noticed from https://github.com/Tencent/puerts/blob/master/unity/Assets/core/upm/Runtime/Src/Default/Utils.cs#L183 that when il2cpp is enabled generics are ignored). This question is mainly aimed at understanding how puerts handles MakeGeneric calls when $generic is used and if it will cause issues then I also have a follow up question about disabling $generic without having to modify the Puerts library directly.

  • I understand that Task can be wrapped as a promise to use in JS/TS but if I want to use UniTask which is what most of my apis use I'm assuming that doesn't work out of the box since UniTask doesn't inherit Task. Which I'm guessing is true based on

    but since it seems that code doesn't do explicit checks on the type maybe it will work since UniTask also has the same methods GetAwaiter and UnsafeOnCompleted

  • I am not trying to force C# nomenclature/paradigms, I understand the limitations of JS/TS, my question was related to using C# APIs that get statically wrapped in TS/JS.

Again, thanks for taking the time to answer my questions, this gave me a better understanding of some limitations, and again, these questions are aimed to understand how C# is exposed on JS side and how Puerts worked through the limitations of JS regarding the features I asked about.

Instantiated generic classes that have been statically wrapped are usable, including il2cpp. If UniTask provides methods with the same name, same signature, and same semantics, it doesn't need to inherit from Task. Even if it doesn't provide such methods, any asynchronous operation with a completion callback and an optional error callback can be wrapped as a promise by similar way.