Rescript-compiler: More uniform bs.module/scope external

Created on 28 Sep 2017  路  15Comments  路  Source: rescript-lang/rescript-compiler

One recurring question we get is how to bind to a module itself, how to bind to a default, how to bind to a nested value and how to bind to a global one. I'm proposing that we unify these through:

(* var X = require('x'); X.add *)
external add : int -> int -> int = "" [@@bs.require ("x", "add")]
(* bind to the module itself *)
external fs : someType = "" [@@bs.require "fs"]
(* window.location *)
external location : someType = "" [@@bs.require ("window", "location")][@@bs.global]
(* bind to document *)
external dom : dom = "" [@@bs.require "document"][@@bs.global]

Characteristics:

  • It'll always be = "". This makes things much more consistent for newcomers. It's a recurring question of where to put what. Maybe we can choose another format now thanks to this.
  • People also ask whether to use [@@bs.val "Math.imul"] or the bs.scope equivalent, etc.
  • Composes with bs.new and the rest as expected.
  • Unifies bs.module, bs.scope, bs.val under a similar looking API. No bs.module module renaming facility, but that's rather rare. These are still kept for backward compat.
  • Resolves the question "what if I want to bind to a module that's global?" through bs.global, which is easier to remember.
  • Might have some nice opportunities to work with bs.get/set.
discussion

Most helpful comment

attributes are really fragile. can we polish it even more by introducing things like

external module "x" {
    add : (int, int) => int 
}

This would not conflict with native OCaml, since it is unlikely in native we have external module

All 15 comments

I agree with this, I actually ran into this myself after not writing some adhoc bindings for some time I would forget the names of them. Also simplifies it for new comers who only have to remember bs.require for everything except for globals.

The downside is all bindings will break (codemod to the rescue) and content on medium, blogs, and docs would have to be updated. Though this hasn't been a blocker before and I really think this would be a great change!

Nono, we keep the current ones for backward compat. I'll clarify this

Awesome, similar to what we did for the jsx ppx changes? that way people have time to update?

We can just leave them around and put a deprecation note on them in the docs, then gradually remove them from the docs, then remove it in bs 2 or 3 or something.

I'm for the consolidation of ideas, but against using require as the word that unifies things. @@bs.require.global is an oxymoron in that you can't require a global value. Coming from JS, this seems confusing. Everything else about this proposal is awesome :)

I agree, I was also thinking this would be could be confusing for adding bs.raw snippets that use require for some css or other types of files. Could just be bs.get & bs.getGlobal, unless bs.get is already necessary which I think it is used elsewhere

yup, it is for getters and setters, nvm

What's the benefit of bs.reguire.global over just bs.global?

Would it also be possible to use a more light-weight dot-notation instead of a tuple? E.g. [@@bs.require.global "window.location"]. Just need to split on ".".

dot + string would have been a nice DSL, but it's not extensible if you want to rename a field or something, like the current [@bs.module ("foo", "F")] does. But then again I also said it wasn't used, hummm...
I'll change bs.require.global to bs.global. This removes the need for bs.val right?*

* Except the second note here but meh

Some more support for the unification & API that doesn't use the = "" part: https://github.com/salamynder/bs-mithril-test#dont-know-how-to-call-function-in-obj-ie-this-structure

Rather typical question.

I've turned bs.global into an optional attachment to bs.require. Seems better this way

attributes are really fragile. can we polish it even more by introducing things like

external module "x" {
    add : (int, int) => int 
}

This would not conflict with native OCaml, since it is unlikely in native we have external module

I'd rather we revamp the FFI (right now it's a small pain to teach them) to also serve the vanilla ocaml userbase, then think about sugar coating. This new syntax might not be that stable either

I'm for the consolidation of ideas, but against using require as the word that unifies things. @@bs.require.global is an oxymoron in that you can't require a global value. Coming from JS, this seems confusing. Everything else about this proposal is awesome :)

I am with @rickyvetter ... I don't like the bs.require keywording for global values...
Ideally I would also like something like this:

(* window.location *)
external location : someType = "" [@@bs.global ("window", "location")]

The rest looks quite sane to me :-)

Hey @bobzhang after writing a ton of bindings to libraries that nest things, I wish it was easier to figure out how to do:

[@bs.module "firebase/app"]
[@bs.scope ("firestore", "Timestamp")]
external makeTimestampFromMillis: float => timestamp = "fromMillis";

Ideally, it'd be something like

[@bs.module "firebase/app"]
external makeTimestampFromMillis: float => timestamp = "firestore.Timestamp.fromMillis";

And we can make the much less frequent case of needing firebaseApp["*crazy_string_*"] have a harder but consistent syntax like

[@bs.module "firebase/app"]
[@bs.as "*crazy_string*"]
external crazyString: float => timestamp = "";
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bobzhang picture bobzhang  路  4Comments

cknitt picture cknitt  路  5Comments

TheSpyder picture TheSpyder  路  5Comments

paparga picture paparga  路  5Comments

zhzhang picture zhzhang  路  4Comments