Rescript-compiler: Allowing dashes and other characters in the string literal type on reason and ocaml using an extension point

Created on 4 Aug 2020  ·  29Comments  ·  Source: rescript-lang/rescript-compiler

This is not possible atm, and it is a blocker to making real-world use of the new feature that compiles poly variants to string literals. Napkinscript provides sugar for this, but reason doesn't and OCaml will probably never incorporate a language feature for this. Here an example of how this can work:

let encoding: [> | `utf8 | `ascii | `utf16 | [%bs.string "bla-bla"] ] => int =
  fun
  | `utf8 => 0
  | `ascii => 1
  | `utf16 => 2
  | [%bs.string "bla-bla"] => 3
  | other => 4;

Due to structural typing we can't alias this once in a type definition (perhaps we can have some kind of converter functions to achieve this?), but having the extension point at least makes it possible to express the literal.

enhancement

Most helpful comment

Everything as been said.
I will just insist on the fact that [bs.string] need to be inline, so we have tons of copy pasting. Like a lot. And every bindings for every lib that accept "generic" props (eg: React Native View props, & a lot of lib do that), we need to keep this in sync & that's a lot of hand work (our current "trick" is to add comment like // View props to remember to keep that in sync, but as human we do mistake too often...)

All 29 comments

The main concern is that the error message may be a bit leaky.
Alternative syntaxes: "bla-bla" [@attr-name]

You can rewrite this with an internal ppx with the correct locations? What's the problem with error messages?

The main concern is that the error message may be a bit leaky.
Alternative syntaxes: "bla-bla" [@attr-name]

I don't think that is valid syntax

You can rewrite this with an internal ppx with the correct locations? What's the problem with error messages?

so when you get a type mismatch, the type needs to be printed, in that case you need do some reverse engineering to print it back to extension syntax

You can rewrite this with an internal ppx with the correct locations? What's the problem with error messages?

so when you get a type mismatch, the type needs to be printed, in that case you need do some reverse engineering to print it back to extension syntax

Isn't that also something that needs to happen for the napkin syntax?

it is done by napkin itself. It's a minor issue though

On Tue, Aug 4, 2020 at 6:13 PM Jaap Frolich notifications@github.com
wrote:

You can rewrite this with an internal ppx with the correct locations?
What's the problem with error messages?

so when you get a type mismatch, the type needs to be printed, in that
case you need do some reverse engineering to print it back to extension
syntax

Isn't that also something that needs to happen for the napkin syntax?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/BuckleScript/bucklescript/issues/4595#issuecomment-668510268,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAFWMK6IIQBTO3LYGQ5J2TDR67NNTANCNFSM4PUGWDFA
.

--
Regards
-- Hongbo Zhang

Ok great to hear! Thanks for considering this proposal.

Is there a concrete use-case of this?

Is there a concrete use case of string literals without this feature?
Interoperability is the reason string literals exist. Now we can't bind to anything that is not a valid poly variant literal.

Which is most strings that you want to bind to in practice. I can give countless examples of libraries, but I think it's intuitive?

As a rule of thumb, we try to introduce a language-wide feature only if there are widely applicable and concrete use-cases. You can give an example of a library

Reason React Native

Which string?

As a rule of thumb, we try to introduce a language-wide feature only if there are widely applicative and concrete use-cases. You can give an example of a library

This is a bad rule. If you cater for only 80% of use cases anyone will run into a use-case that is not possible in the language and hit a dead end.

Which string?

Many strings...

I am trying to get work done. It might not be the prettiest solution, but we need these escape hatches to use this in the real world. You will only bump into this if you try these constructs in a real app or library not some kind of contrived example. The language authors have to understand that in order to get traction, you need these escape hatches. Which is mainly why Bucklescript was so great.

Do I really need to show that there exist string literals with dashes spaces etc. in javascript libraries. Isn't that quite obvious?

I've precisely been asking for a real library example so far. The only contrived example in this issue is your original snippet...

@jfrolich @chenglou this feature has been out for like 2 days.. would it make sense to get some more feedback / hands-on experience with the current state until we decide on adding more features?

I looked at the ReasonReactNative API and checked some bindings to get an idea on what you are referring to... i find things like this:

~clearButtonMode: [@bs.string] [
                        | `never
                        | [@bs.as "while-editing"] `whileEditing
                        | [@bs.as "unless-editing"] `unlessEditing
                        | `always
                      ]

I guess your complaint is that you want to use the newest feature to represent that clearButtonMode, right?

Currently trying to understand what's the problem here, because we went from "would be useful to express dashes in poly-variants" to "I can't build any real world apps with that feature", which I don't believe is true? Or did the new representation break any existing code for you?

@jfrolich @chenglou this feature has been out for like 2 days.. would it make sense to get some more feedback / hands-on experience with the current state until we decide on adding more features?

You are right. I don't expect anything to be implemented right away.

I was mainly annoyed that this feature was introduced in a blog post introducing "string literals" as a new language feature, raising the expectations that this could be used to bind to arbitrary string literals in JavaScript. That's kind of overpromising what it can actually do. It can still be useful in limited use-cases. But in many cases, the variant that you're trying to bind to will have a form that can not be expressed as a polyvariant. I think it would be better to launch with a proposition that supports all literals (even if it's not the most elegant solution if you need a dash), and not have a disappointing experience for people that are excited about it, try to use it and end up in a situation where they need to bind to a literal that is not supported with is no alternative solution. It's maybe 10% extra work, but it can enhance the initial experience quite a bit.

I am also still a bit annoyed at the blog post causing a lot of confusion. Aiming the blog post at new users while this feature is probably most useful to library authors. Using a new name for the feature "string literal", that isn't used in any documentation. With examples in Reason but linking to OCaml documentation instead of documentation that is written with examples in Reason (probably better to write a longer more detailed description and have that as part of the official Bucklescript documentation). Asking for feedback for the blog post, with me investing time and writing lengthy feedback with these points and many others to improve the blog post, and basically not addressing anything except some spelling mistakes. Don't ask for feedback if you are not going to do anything with it.

I care about this because I am betting my company on this technology, and try to make the ecosystem a success by investing a lot of my free time, trying to make it more accessible and useful for (new) users. The tech is amazing, but we need to be deliberate how we communicate. And the quality of the user experience. Bucklescript is solid, but a lot of aspects are sloppy and confusing to users. We need to aim higher in that regard. Fixing this is how we get traction.

About the feature itself:

I was mainly enthusiastic because we can get rid of the [@bs.string], and this allows more simplification because we cannot use [@bs.string] everywhere. An example being:

image

Hi, the feature is a reasonable feature request, the examples you just
provided is great. These examples would help justify the implementation a
little bit.

Let’s not get emotional, sorry about the mis-communication

Jaap Frolich notifications@github.com于2020年8月4日 周二下午8:50写道:

@jfrolich https://github.com/jfrolich @chenglou
https://github.com/chenglou this feature has been out for like 2 days..
would it make sense to get some more feedback / hands-on experience with
the current state until we decide on adding more features?

You are right. I don't expect anything to be implemented right away.

I was mainly annoyed that this feature was introduced in a blog post
introducing "string literals" as a new language feature, raising the
expectations that this could be used to bind to arbitrary string literals
in JavaScript. That's kind of overpromising what it can actually do. It can
still be useful in limited use-cases. But in many cases, the variant that
you're trying to bind to will have a form that can not be expressed as a
polyvariant. I think it would be better to launch with a proposition that
supports all literals (even if it's not the most elegant solution if you
need a dash), and not have a disappointing experience for people that are
excited about it, try to use it and end up in a situation where they need
to bind to a literal that is not supported with is no alternative solution.
It's maybe 10% extra work, but it can enhance the initial experience quite
a bit.

I am also still a bit annoyed at the blog post causing a lot of confusion.
Aiming the blog post at new users while this feature is probably most
useful to library authors. Using a new name for the feature "string
literal", that isn't used in any documentation. With examples in Reason but
linking to OCaml documentation instead of documentation that is written
with examples in Reason (probably better to write a longer more detailed
description and have that as part of the official Bucklescript
documentation). Asking for feedback for the blog post, with me investing
time and writing lengthy feedback with these points and many others to
improve the blog post, and basically not addressing anything except some
spelling mistakes. Don't ask for feedback if you are not going to do
anything with it.

I care about this because I am betting my company on this technology, and
try to make the ecosystem a success by investing a lot of my free time,
trying to make it more accessible and useful for (new) users. The tech is
amazing, but we need to be deliberate how we communicate. And the quality
of the user experience. Bucklescript is solid, but a lot of aspects are
sloppy and confusing to users. We need to aim higher in that regard. Fixing
this is how we get traction.

About the feature itself:

I was mainly enthusiastic because we can get rid of the [@bs.string], and
this allows more simplification because we cannot use [@bs.string]
everywhere. An example being:

[image: image]
https://user-images.githubusercontent.com/579279/89293212-1c7fe580-d690-11ea-96c6-b93217d7c7e8.png


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/BuckleScript/bucklescript/issues/4595#issuecomment-668576791,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAFWMK75BWDXVQC4MBX5BW3R677ZVANCNFSM4PUGWDFA
.

>

Regards
-- Hongbo Zhang

Let’s not get emotional, sorry about the mis-communication

Sorry for the tone to be emotional. And I don't want to complain on the sidelines, and really help move this project forward. But I just wanted to clarify my stance here. Hopefully you understood a bit more where I am coming from. Cheers!

@jfrolich have some thoughts about the implementation.
Changing the parser actually is the least work to do, I had a look at the ocaml/refmt grammar, there's no conflict, so I think maybe a couple of lines changes. Proposed syntax : `"hello-world"
Why it is not that great to use extension? It appears in multiple places, here's a few:

type t = [ `"hello-world"]
let simple = `"hello-world"
let complex = `"hello-world" (1,2)
let f = 
  match x with
  | `"hello-world"
  | `"hello-world" (1,2) -> ...

Can you talk with upstream to gauge their interest?

Sure. One "problem" I can identify is that when we upgrade refmt inside of Bucklescript is that it will be quite a big update as the current one is quite an old version. But perhaps we can distribute Reason separately, so it's easier to do these kind of syntax upgrades?

Based on my observation, most work of refmt is catching up latest releases of ocaml native.

But perhaps we can distribute Reason separately,

That's something I wish eventually, but doing this currently would cause a mess due to version mismatch etc

That's something I wish eventually, but doing this currently would cause a mess due to version mismatch etc

That is good to hear. Was wondering if this route remains supported.

~clearButtonMode: [@bs.string] [
                        | `never
                        | [@bs.as "while-editing"] `whileEditing
                        | [@bs.as "unless-editing"] `unlessEditing
                        | `always
                      ]

I guess your complaint is that you want to use the newest feature to represent that clearButtonMode, right?

Yes, it would be great to be able to define something like

type  clearButtonMode = [
  | `never
  | `"while-editing"
  | `"unless-editing"
  | `always
]

for the following reasons:

  1. If a user wants to wrap the TextInput component and pass the clearButtonMode through, he could use this type and not have to redeclare it.
  2. The type definition for all props in View taking polymorphic variants currently needs to be repeated for all subclasses of View (as bs.string/bs.as only work within the external definition). It would be much better to be able to define the type in one place.
  3. We would be using exactly the same strings as in the JS API (while-editing instead of whileEditing).
  4. We could get rid of some workarounds using abstract types and bs.inline like @jfrolich mentioned.

/cc @MoOx

Without supporting the -, the new "polyvars as strings" feature is of limited use for the react-native bindings, and I guess this will be similar for many other JS libs.

Syntax-wise, I like the

`"hello-world"

as proposed by @bobzhang, or

#"hello-world"

in .res as proposed in https://github.com/BuckleScript/syntax/issues/76.

I also agree with @jfrolich that it seems weird that the blog post suddenly uses the term "string literals" for polymorphic variants.

Everything as been said.
I will just insist on the fact that [bs.string] need to be inline, so we have tons of copy pasting. Like a lot. And every bindings for every lib that accept "generic" props (eg: React Native View props, & a lot of lib do that), we need to keep this in sync & that's a lot of hand work (our current "trick" is to add comment like // View props to remember to keep that in sync, but as human we do mistake too often...)

I did talk with @jordwalke about this. The gist is that it would be great if the template strings would compile to an AST that OCaml could still access even if it's ugly. @bobzhang any thoughts on this?
The naive implementation when creating #"hello-world" is that OCaml cannot construct such a poly variant. Is there some name mangling we can do to support that?

@jfrolich I think Bob asked earlier if you could talk to upstream to gauge their interest on this, I believe he was referring to OCaml, i.e. would they be interested in supporting `"hello-world"?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

paparga picture paparga  ·  5Comments

zhzhang picture zhzhang  ·  4Comments

cknitt picture cknitt  ·  5Comments

frank-dspeed picture frank-dspeed  ·  4Comments

tanaka-de-silva picture tanaka-de-silva  ·  5Comments