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

Change of direction #214

Open
pbiggar opened this issue Jul 28, 2021 · 7 comments
Open

Change of direction #214

pbiggar opened this issue Jul 28, 2021 · 7 comments
Labels
planning Maintenance discussion where releases are planned and tracked

Comments

@pbiggar
Copy link
Member

pbiggar commented Jul 28, 2021

After a few years experience with this library, and given the changes in the ecosystem over that time, I think it would be wise to change the purpose of Tablecloth somewhat.

Problem

I think the original goal - to be able to reuse code between bucklescript and OCaml - is not as good a goal as I initially thought.

My experience with trying to share code between the platforms has not been great - we only share some very basic types and very little logic. We tried to share some less basic types, but we needed to use ppxes that were only available on one or another, and used different annotations in each.

Moreover, the goal of sharing types on server and client is less useful than originally imagined. Client and server move at different paces, with for example the server able to change fairly instantly while clients take longer, while also the server has serialization concerns that cause types to sometimes persist much longer than on the client.

To add to this, ReScript and OCaml are diverging more and more. ReScript is very much focussing on its mission of supporting JS, and over time has focused much less on any connection to OCaml, including - significantly - sticking with an older version of the OCaml compiler. The focus on t-first also means that trying to overlay a t-agnostic library doesn't hold up as well.
ReScript also has a formidable standard library in Belt - I notice that Tablecloth's Map does not have a compatible type with the Rescript Map.

At the same time, OCaml is moving forward at a good pace too. It has moved forward many versions, as has Base/Core. I haven't perceived any changes that would affect us, but I'm sure they will come.

Solution

As I look to how we actually use Tablecloth at Dark, the most valuable thing has not been reusing code (as stated above, this has been quite a bad experience really), but rather having the same APIs available on all platforms. It is annoying when using multiple MLs to have to look up what the function is called in F# vs OCaml vs ReScript.

So I'd like to switch Tablecloth to a somewhat purer form of its original goal: to be an overlay that provides the same API on many ML platforms: OCaml, ReScript, and F# (and in the future other MLs too).

This would mean:

  • the primary function of the library is to have functions of the same name on each platform (for example, all platforms would have a Map.values or String.join function), with the signature being close but also closely tied to the platform (t-first in ReScript and t-last in F#, for instance)
  • code reuse is not a goal, just API similarity
  • functions should only be named in the style of what is idiomatic on that platform (camelCase on Rescript and F#, snake_case in OCaml) - this is a problem as having two names in each cloggs up the autocomplete which annoys people
  • Set and Map types would be aliases for the idiomatic Set/Map used on each platform, not our own type

Comments?

I'd love some comments on this proposal. It is a move away from how we designed tablecloth, but I think it is more appropriate given how the ecosystem has been moving.

@pbiggar
Copy link
Member Author

pbiggar commented Jul 28, 2021

@Dean177 particularly interested in your thoughts

@Lomand
Copy link
Contributor

Lomand commented Oct 26, 2021

Sounds amazing, is there any roadmap with intermediate steps of this transition? Would love to contribute

@pbiggar
Copy link
Member Author

pbiggar commented Oct 27, 2021

My rough idea of a roadmap:

  • release current version
  • add F# version from https://github.com/darklang/dark/tree/main/fsharp-backend/src/Tablecloth
  • release again
  • now start changing direction:
    • remove rescript and f# snake_case versions
    • remove ocaml camlcase functions
    • make f# functions t-last
    • make ocaml function t-last
    • add ocaml-related ppx things as a separate library
    • make rescript functions t-first
    • remove custom tablecloth maps
    • remove custom tablecloth sets

@Lomand
Copy link
Contributor

Lomand commented Oct 30, 2021

Ok, I'll try to help you with some of the points:

✅ Remove rescript snake_case versions (PR #233)
✅ Remove ocaml camlcase functions
⬜ Make ocaml function t-last
⬜ Make rescript functions t-first

@Lomand
Copy link
Contributor

Lomand commented Dec 24, 2021

@pbiggar starting the work on migrating rescript functions to be data-first, just want to clarify your vision on the design.

From my understanding, moving to data-first will eliminate labeled ~f argument, but other labeled arguments will be preserved, since they provide clarity, and not data agnostisity.

Example:

[| 1; 2; 3; 4; 5; 6 |] |. filter ~f:Int.isEven becomes [| 1; 2; 3; 4; 5; 6 |] |. filter Int.isEven

map2 ~f:( + ) [| 1; 2; 3 |] [| 4; 5; 6 |] becomes map2 [| 1; 2; 3 |] [| 4; 5; 6 |] ( + )

but
sliding [| 1; 2; 3; 4; 5 |] ~size:2 ~step:3 and

42 |. repeat ~length:2 will stay the same

Such functions will still be data-agnostic, but this will be a side effect, not a feature.

Did I understood your vision correctly?

@pbiggar
Copy link
Member Author

pbiggar commented Dec 24, 2021

That's a good question. In OCaml, t-last is desirable, but also labelled arguments are the norm, so it makes sense in OCaml to keep the labels where they are.

In F#, there are no labels, so we just need to make sure everything is t-last.

In ReScript, I'm not so sure. ReScript supports labelled arguments for sure: is it normal to use labelled arguments? That said, for ~f, the f argument is not the t in t-first (that would be the list, map, etc). It could be that the only thing to change are things like map union and list concatenation that take two arguments of the same type (though I'm speaking off the cuff there).

@pbiggar
Copy link
Member Author

pbiggar commented Oct 11, 2022

In ReScript, I'm not so sure. ReScript supports labelled arguments for sure: is it normal to use labelled arguments? That said, for ~f, the f argument is not the t in t-first (that would be the list, map, etc). It could be that the only thing to change are things like map union and list concatenation that take two arguments of the same type (though I'm speaking off the cuff there).

Having thought more about this, we should remove labels for rescript, as they're not idiomatic.

@pbiggar pbiggar added the planning Maintenance discussion where releases are planned and tracked label Oct 11, 2022
@pbiggar pbiggar pinned this issue Oct 11, 2022
@pbiggar pbiggar added this to the 0.1.0 milestone Oct 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
planning Maintenance discussion where releases are planned and tracked
Projects
None yet
Development

No branches or pull requests

2 participants