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

[Snake Island] How to write bindings for new targets #2779

Open
alfonsogarciacaro opened this issue Jan 28, 2022 · 3 comments
Open

[Snake Island] How to write bindings for new targets #2779

alfonsogarciacaro opened this issue Jan 28, 2022 · 3 comments

Comments

@alfonsogarciacaro
Copy link
Member

This is a continuation of the discussion started here. Not sure about Rust, but because Python and Dart imports work in a similar way to JS, we can reuse the Import attributes from Fable.Core, with some differences. For reference, there's also a discussion about how to improve bindings for JS here.

For Dart (I'm still learning the language so this may change) I'm considering to use static classes to represent external modules/packages. @Nhowka has suggested to just use modules, but this may be difficult for a couple of reasons:

  • As soon as you need an optional argument in one function you need to use a class. So it may happen that you write bindings as a module an to add a new function you need to rewrite the whole module into a class (also likely breaking call sites). Even if this is acceptable we would end having some bindings written as classes and some as modules, creating inconsistencies.
  • I don't remember exactly but I think I already look into this once and it's not trivial to access the attributes of the enclosing module from a class reference.

However, it's true using classes makes it more difficult to declare types within the external modules. It's a bit clumsy and I still need to test it, but I think we can take advantage of F# ability to have a module and a class with the same name at the same level:

open Fable.Core

let [<Literal>] private PATH = "package:test/test.dart"

module Test =
    [<ImportMember(PATH)>]
    type Assertion<'T>() =
        class end

open Test

[<ImportAll(PATH)>]
type Test =
    static member test(msg: string, f: unit -> unit): unit = nativeOnly
    static member expect(actual: 'T, assertion: Assertion<'T>): unit = nativeOnly
    static member equals(value: 'T): Assertion<'T> = nativeOnly

Note the top-level class uses ImportAll and the inner types use ImportMember.

@ncave
Copy link
Collaborator

ncave commented Jan 28, 2022

@alfonsogarciacaro Import classes don't need to always be static, right?

@Nhowka
Copy link
Contributor

Nhowka commented Jan 28, 2022

For Dart my main concern was about the methods and fields that exist outside classes, but you are right about being unable to represent the optional arguments if we went that way. Different Import attributes for differentiating top-level from classes might work.

@alfonsogarciacaro
Copy link
Member Author

@ncave No, they can have instance members as well, in that case, the generated code is very similar to the one for interfaces (no mangling, accessing the method directly from the instance) except for the constructor.

@alfonsogarciacaro alfonsogarciacaro changed the title [Beyond] How to write bindings for new targets [Snake Island] How to write bindings for new targets May 11, 2022
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

No branches or pull requests

3 participants