ReScript offers a powerful functional programming paradigm that virtually eliminates runtime type errors, making it a power tool for developers building mission-critical JS systems.
ReScript’s type system is based on the Hindley-Milner algorithm. It is designed so that if the code passes the compiler, it is mathematically proven that a value will never be of a different type than what the system expects. There is no null or undefined in ReScript; everything must be explicitly handled via the Option type.
Currently, the ReasonML track is significantly outdated; it lacks a Melange build system and relies on an oversized Docker image. Introducing a native ReScript track would provide a modern, relevant, and efficient learning experience that aligns with current industry standards.
A large chunk of the work is already done. Migrating existing ReasonML exercises to their ReScript equivalent will give users a decent number of exercises to being with. Of course there will need to be a test runner created, which no doubt will be the love child of the ReasonML and JavaScript ones.
I have taken the work that has been done so far and brought it up to the most recent version, ensuring all tests pass. So there is a semi-working repo on my machine at the moment, complete with the git history of all those who contribute thus far.
In the meantime I will read the links you have sent (in the morning, its late) and go from there.
I have essentially reworked what was done previously, with most of the tooling from the existing ReasonML track from where the ReScript branch was created.
I don’t see the test.yml that is mentioned in the linked docs, but it looks as thought this is covered in main.yml and then there will need to be a test runner created.
I am happy to push work done so far to the ReasonML branch, if someone wants to look over it. It should be a fairly straightforward installation and testing procedure, using make.
How similar/different is ReScript vs TypeScript? I thought ReScript was a way to revive ReasonML but now that I’m digging into it, it sounds like it might be much more akin to TypeScript?
My understanding is that ReScript happens to compile to JavaScript like TypeScript, but otherwise it’s more similar to ReasonML than TypeScript.
ReScript isn’t trying to be JavaScript with type annotations. TypeScript has a gradual typing system so you could introduce types over time, but ReScript is all or nothing. Since it’s a ML family language, data structures are immutable by default. In TypeScript, you could have const to avoid reassigning a reference, but you could still update the data inside most data structures.
To clarify, is the proposed ReScript track going to be offered alongside the existing ReasonML track or instead of it? We rarely remove existing tracks since I’ve been contributing, but I know of two times recently we did.
We deprecated ClojureScript because it was deemed essentially Clojure targeting a new compiler (JavaScript instead of Java) so it doubled the amount of maintainer work for little gain. You could copy solutions from Clojure to ClojureScript with minimal changes and still pass the tests. That doesn’t seem like it applies here if we haven’t been able to easily migrate the ReasonML exercises to ReScript within the confines of that track.
The other major deprecation was PL/SQL where the track had no test runner and it was determined that it would take a lot of effort to modernize the track. I believe the discussion about deprecating PL/SQL predated the SQLite track being proposed, but essentially SQLite replaced it as an easier-to-maintain track. So I’m not sure that’s necessarily a precedent here.
If the proposal for ReScript is a new track alongside ReasonML, I would recommend sharing the example test runner/exercise here as part of the proposal step. Typically this is done as a new non-Exercism git repo. If it’s in a branch of the ReasonML repo, that might make it a bit more challenging to understand what parts of the branch are ReasonML vs ReScript.
ReScript has diverged too far from ReasonML to be considered an update to the ReasonML track now. Therefore it would be its own track.
ReasonML still uses OCaml as its backbone, whereas ReScript compiles to JavaScript.
https://github.com/TheRealOwenRees/reasonml - the work done so far is in the rescript branch here, which is an update of the work that was done previously but brought up to modern ReScript. I have not got as far as a test runner yet because I do not yet know where we stand.
Adapting previous work by tejasbubane, here’s the proposed Hello World stub and test file.
Hello World stub
let hello = () => "Goodbye, Mars!"
Hello World example
open Test
Hello, World stub
let stringEqual = (~message=?, a: string, b: string) =>
assertion(~message?, ~operator="stringEqual", (a, b) => a == b, a, b)
test(""Say Hi!"", () => {
stringEqual(~message="Say Hi!", HelloWorld.hello(), "Hello, World!")
})
Can we move this thread over to Building Exercism? This isn’t really a bug nor a feature request.
I think we’ve addressed why ReScript is different from ReasonML and this post now provides the customary Hello World example. @ErikSchierboom, if you concur, can we get an exercism/rescript repo spun up? I’ll help TheRealOwenRees with building out the track.
Since we’re starting fresh, now might be an appropriate time to introduce a test generator. I’m personally a fan of Glenn’s approach with MoonScript so maybe something like this can be put in each exercise’s .meta folder. We’d have a script that pulls in the canonical data JSON and passes it to generate, building up a string representing the test suite. The script writes that to the exercise’s test file and then formats it as well.
That gives us a lot of flexibility in translating the canonical data using JS since several exercises might need special handling if we make a generic test suite generator. That’s a bit fiddly in my experience.
Here’s what this might look like for Leap.
export function generate(canonicalData) {
let testSuite = `open Test
open Leap
let isTrue = (~message=?, a: bool) =>
assertion(~message?, ~operator="isTrue", (a, b) => a == b, a, true)
let isFalse = (~message=?, a: bool) =>
assertion(~message?, ~operator="isFalse", (a, b) => a == b, a, false)
`;
for (const testCase of canonicalData.cases) {
const description = testCase.description;
const year = testCase.input.year;
const expected = testCase.expected;
const assertFn = expected ? 'isTrue' : 'isFalse';
testSuite += `test("${description}", () => {
${assertFn}(~message="${description}", isLeapYear(${year}))
})
`;
}
return testSuite;
}
I agree, that would be a nice feature, and keeping each generator per exercise would simplify it. The OCaml generic test generator gave us quite a large special_cases file in the end.
I will look at that once I have addressed the rest of your feedback, and something to check that this file exists too.
Test generator - I assume something along the lines of comparing the tests.toml against the canonical data and write tests for all those not ignored? This would mean pulling in the problem specification repo? If so I will add that to the readme as well.