There's no need to pick! Reason and OCaml share the exact same semantics (i.e. how the code runs). Only the syntax differ. Carry Reason-tools around so that you can freely convert between the two syntaxes. A Reason tutorial is an OCaml tutorial, vice-versa. In the terminal, you can have these alises:
# converts ocaml code into reason
alias mlre="pbpaste | refmt --parse ml --print re --interface false | pbcopy"
# converts reason code into ocaml
alias reml="pbpaste | refmt --parse re --print ml --interface false | pbcopy"
They'll take your code from the (macOS) clipboard, convert it, and paste it back into your clipboard! Swap out pbpaste/pbcopy with your system's clipboard functions.
We compile to JS very well. Think of what project you'd usually make if it was pure JavaScript; try porting/writing that in Reason + BuckleScript instead! We recommend trying to make concrete, end-user projects (e.g. a little command line util) rather than infra-level projects (e.g. a boilerplate generator). The latter category requires expertise and understanding idiomatic Reason code.
See here. Reason's a syntax for OCaml and supports all its features. BuckleScript compiles OCaml/Reason code into JavaScript.
print_endline
, string_of_int
functions come from?They're from the standard library, pre-open
ed during the compilation of your file. This is why you see them in scope.
If you're compiling to JavaScript through BuckleScript, you can use the JS console.log
through Js.log
. If you're compiling to native, you'll need something like ppx_show. A future OCaml feature (called modular implicit) will solve this directly in the language.
See here.
Most JS libraries should easily work under Reason + BuckleScript. On the native side, since Reason's just a syntax transform: yes, they work with Reason too. But the native workflow is currently work-in-progress and needs polish.
We do compile to native, but the native workflow is currently work-in-progress. At this time, we recommend compiling to JS through BuckleScript and use the bindings at reasonml-community or somewhere else.
First, if you're not interfacing with any library that uses promises, you can simply use callbacks. Everyone gets them and they're performant.
If you need to bind to a JS library that uses promises, or communicate with such library, you can use BS's bindings to promises. There's also potential to have some syntactic sugar in the future. In the long run, we'd like to implement a spec-compliant promises implementation in OCaml/Reason proper, so that the compiler optimizations could kick in.
For a more idiomatic OCaml solution: on the native OCaml side, we have lwt and Async. We don't use them in web right now, but we might in the future.
Some of OCaml's language features (not just types) might be able to defer the need for unit testing until later. In the meantime, for compilation to JS, we're working on Jest bindings. We'll look into using Jest for native too, if Jest is written using Reason in the future (no concrete plan yet). OUnit is a good, small native OCaml testing library right now.
.merlin
file at the root of my project?That's the metadata file for Merlin, the shared editor integration backend for autocomplete, jump-to-definition, etc. For the JavaScript Workflow, bsb
the build system generates the .merlin
for you; You don't need to check that into your version control and don't have to manually modify it.
import
or require
in my file; how does module resolution work?Reason/OCaml doesn't require you to write any import; modules being referred to in the file are automatically searched in the project. Specifically, a module Hello
asks the compiler to look for the file hello.re
or hello.ml
(and their corresponding interface file, hello.rei
or hello.mli
, if available).
A module name is the file name, capitalized. It has to be unique per project; this abstracts away the file system and allows you to move files around without changing code.
Not currently. You'd have to do the manual translation. Alternatively, try using JS objects directly
Generally speaking, we recommend binding to the JS library thinly rather than thickly and idiomatically; better stay lightweight and catch conversion mistakes.
See also our JS interop guide.
Not currently. Though you can output JS artifacts alongside your Reason files. See the in-source
option here, in package-specs -> package-spec -> module-format-object.
Are you using a third-party module? If you're compiling to JS, did you add the dependency in your bsconfig.json
's bs-dependencies
field? Also, did you do bsb -make-world
? bsb
by default only build the root project itself for performance.
Additionally, don't forget to add the source folders into your bsconfig.json
! For performance, bsb
doesn't automatically and recursively build nested folders.
Some | None
, contents
, Array
, List
and all of these special? Where do they come from?They're ordinary variants/records/module definitions that comes with the standard library, open
ed by default during compilation out of convenience.
_
or _foo
) mean?Say you have List.map (fun item => 1) myList
. The argument item
isn't used and will generate a compiler warning. Using fun _ => 1
instead indicates that you're intentionally receiving and ignoring the argument, therefore bypassing the warning. Alternatively, fun _item => 1
has the same effect, but indicates more descriptively what you're ignoring.
MyModule.t
I keep seeing?Assuming MyModule
is a module's name, t
is a community convention that indicates "the type that represents that module, whatever that means". For example, for the Js.String
module, String.t
is the type carried around and representing "a string".
Js_promise
and then a Js.Promise
? What about Js_array
, Js_string
and whatever else?As a convention, Js_foo
is the actual module, and Js.Foo
is just an alias for it. They're equivalent. Prefer Js.Foo
, because that's the official, public module name.
They will one day. In the meantime, help us ship more Reason code! The popularity will help funnel more OCaml contributions. The less the OCaml folks need to worry about low-hanging fruits, the more they can focus on great research and execution!
BuckleScript is optimized for performance across the whole stack. You can try slowing it down by adding a dozen layers of indirections and metaprogramming. Try:
The OCaml community frequently uses file extensions to distinguish between types of source, artifacts, and metadata, depending on your build target (native/bytecode/JavaScript). The following is a overview of some of the file extensions you may come across:
.ml
: OCaml source file.mli
: OCaml interface file; determines which parts of the matching .ml
file are visible to the outside world.re
: Reason source file. Like .ml
, but for Reason.rei
: Reason interface file. Like .mli
, but for Reason.cmi
: Compiled interface (.rei/mli) file.cmx
: Compiled object file for native output (via ocamlopt).cmo
: Compiled object file for bytecode output.cmj
: Compiled object file for web (via BuckleScript).cma
: Library file for bytecode output (equivalent to C's .a files).cmxa
: Library file for native output.cmt
: Contains a "Typedtree" – basically the AST with all type info.cmti
: Just like a .cmt file, but for interface files.cmxs
: Dynamically loaded plugin (for native compilation).o
: Compiled native object file.out
: Conventional name/extension for final output produced by ocamlc/ocamlopt (e.g. ocamlc -o myExecutable.out
).mll
: ocamllex lexical analyzer definition file.mly
: ocamlyacc parser generator definition file.mldylib
: Contains a list of module paths that will be compiled and archived together to build a corresponding .cmxs
target (native plugin).mliv
: Batteries-specific files for some custom preprocessing..mllib
: Ocaml library (cma and cmxa).mlpack
: Ocaml package (cmo built with the -pack flag).mlpp
: Extlib-specific files for some custom preprocessing.mltop
: OCamlbuild top-level file, used by OCamlbuild to generate a .top file.odocl
: OCaml documentation fileIf some of those explanations are still a bit cryptic, here are expansions on some of the terms used above:
There is more information and context for many of these file extensions on the OCaml site and in this mailing list post. There are also deeper dives on native and bytecode compilation that contain more detailed descriptions in the OCaml manual.