Fable
Fable copied to clipboard
[Snake Island] How to write bindings for new targets
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
ImportAlland the inner types useImportMember.
@alfonsogarciacaro Import classes don't need to always be static, right?
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.
@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.