In summary, Reason [2] is a new language (correction: interface to OCaml) that shares a part of the OCaml compiler toolchain and runtime. I don't know of any language that uses a similar approach, that is, plugging into an existing compiler toolchain. I guess a reasonable yet inaccurate analogy would be Reason -> OCaml is like Elixir -> Erlang or Clojure -> Java.
I hope Reason can provide OCaml with the extra push needed to bring it into the mainstream PL space and more widespread adoption.
Feel free to take a look at some Reason in the wild, used inside of the Infer project at Facebook:
https://github.com/facebook/infer/tree/master/infer/src/IR
Apart from that, although syntax is the "user interface" to a language, and user interfaces are very important, there really is so much to a language beyond the syntax. I see Reason's syntax as a way to make the really good parts of OCaml exposed to a wider audience, while making existing OCaml developers more productive in their editors.
Some things you might appreciate about OCaml's core language (which Reason provides a new interface to):
- World class pattern matching.
- Excellent type inference.
- Bare metal compilation without a VM, but alternatively the ability to compile into JS.
- Great predictable performance, even without a ton of performance optimizations (because the runtime is so simple), but take a look at 4.03 which includes a new F-lambda optimization pass. Even without F-lambda the perf is competitive with other systems languages, and F-lambda buys you another good 10-30% reduction in CPU or so.
- Multicore support is progressing. Here's a PR from today to add multicore support to the native backend (https://github.com/ocamllabs/ocaml-multicore/pull/47)
Another major recent advance in OCaml 4.03 (released last month) is the flambda middle layer -- basically an epic inlining and allocation elision pass. See https://blogs.janestreet.com/flambda/ for more on it, but it's already giving 10-20% performance improvement on real world code.
Multicore is also coming soon -- see https://ocaml.io/w/Multicore for a summary of activity there.
Actually, if ocaml "optimized" compiler have shown anything, it's that micro optimizing instructions and register allocation is not as important as once believed. Indeed, for long amongst "sophisticated languages" Ocaml "optimized compiler" was renowned at the same time for the speed of generated code and for the simplicity of its code generation pass, lacking many advanced features found in ghc for instance.
> The OCaml compiler is organized into several stages, which are exposed as libraries. Reason replaces part of the compiler toolchain with a completely new syntax parser that is more approachable, while still fully compatible with the rest of the compiler. Reason also implements a new source printer which integrates into your IDE and the new custom REPL.
So you can abstract the syntax from the runtime, but the semantics are often different per target - e.g. accessing the filesystem in Node.js will be different to C++, due to the non-blocking I/O mechanism.
As an aside, the Haxe compiler is written in OCaml. I think there'd be a delicious juxtaposition if it was re-written in Reason. Writing Reason to generate OCaml to create Haxe to generate Java to generate bytecode...
It should be easy to convert the Haxe compiler into Reason with refmt. Maybe unless if it's using camlp4 syntax extension... But I guess you could add a camlp4 pass before running refmt.
Sure, OCaml isn't even the nicest syntax in the ML family, but I'm not sure whether that's worth it, especially considering that almost any "X-like" language often turns out to be an Uncanny Valley for "X" programmers -- close enough to make some frustrating errors.
I've mentioned elsewhere that the primary goal for now was to get the tooling automated as much as possible, so that when we receive common feedback, we can adapt to that feedback and trivially migrate people's code forward.
I don't think JavaScript's syntax is a selling point and I am someone with a lot of JavaScript experience. I also don't think that OCaml's syntax today is a selling point, and I have a bit of OCaml experience. Both of these syntaxes have evolved over time, working within that limited precious syntactic real estate, trying so very hard to maintain compatibility with decisions made decades ago. Reason's approach is totally different in that it knows we won't get it right on the first shot so it puts into place the tooling for upgrading and beautifying as we learn lessons and take feedback from the community. It places the syntax closer to the user, even if only conceptually.
That being said, the current syntax is not intended to be a JavaScript clone by any means. It actually started in the opposite manner - by taking the top 15 complaints about OCaml's syntax, by experienced OCaml programmers (not JS programmers) and fixing them. There were a couple of things that didn't really matter (such as how you express comments) that were just changed to be more familiar because, well.. simply they don't matter, and even experienced OCaml developers want the largest possible set of people to be able to read their code as long as that comes with little other tradeoffs.
But an advantage I see with the new comment syntax is that there are is that there is no ambiguity what the hell (*) is. At least this.
Maybe that's because it's the first and only thing one can see and therefore it's cheap to have an opinion? Or is it because too many professionals are used to languages which are little more than a syntax on top of a toy evaluator?
When I first try ocaml long ago, I though overcoming the syntax would be a huge challenge (especially since I was using lisp at the time). Surprisingly, I got used to it after the first night, and even started to like it. Just a single data point of course, but it seems useful to warn new programmers that your first impressions on the syntax of a language are just that. Also, your estimation of the time that would be required to learn a new language based on how easily you can parse the syntax at first sight is completely wrong. It took me longer to understand some error messages that the compiler threw at me long after I though I could "speak ocaml" than to build an initial understanding of the syntax (roughly 2 hours).
All of the above, of course, is just a disgruntled and grumpy way to say: despite we all know we don't care about the syntax of any language once we know it, it's still an overly important factor to drive a language adoption (or, in the case of ocaml, disaffection). Therefore, let's hope this new "revised syntax" will help many more programmers discover more sophisticated languages than the industry standards!
Under "Why OCaml?" on the Reason page, it states, "OCaml has a very mature (and still growing) ecosystem for targeting browser and JavaScript environments with a focus on language interoperability and integration with existing JavaScript code," and "Reason‘s non-invasive approach to the OCaml compiler allows Reason code to take advantage of all of the existing OCaml compiler optimizations/backends such as ... and even JavaScript compilation."
It seems like what's being said is that one of the main goals for Reason is to integrate with JavaScript, and it would seem to make sense instead of changing between language syntaxes, you'd want more in common between them, so it makes sense why they are similar. I'm confused as to why you seem to be trying to distance Reason and OCaml from JavaScript, when it definitely seems like the similarity with and integration with JavaScript would be a driving factor in Reason's development now, even if maybe it wasn't in the beginning.
Reason seems really cool, btw.
So I hope this helps explains why many people feel that compiling to JS is important, even if the syntax/semantics of JS are not equally sought after by those same people.
At the same time, we can't overlook that JavaScript has become one of the most popular languages today. If that were the case thirty years ago, I'm sure the syntax for the ML family would have taken that into account somehow, at least to convey the parts of the two languages that actually are similar - even if only for things as simple as comments. So at least in this V0.0.1 of Reason, some of the things that just don't matter tend to look like things that are familiar to a larger set of people.
I think you've picked up on what looks like an inconsistency in messaging so thanks for pointing it out. I can't speak for everyone else who works on Reason, but I see the two major components (compiling to, and resembling) JavaScript to be largely independent. We can want to compile to JavaScript for totally different reasons than we want some pieces of the grammar to resemble JavaScript and I believe that is the case here. The pieces that currently resemble JavaScript are that way simply because those pieces don't matter too much and why not just be familiar? There are certain syntax features of JS that members of the JS community would tell you were mistakes, and we're not looking to recreate them just for the sake of being like JS.
EDIT: Hosting a Meetup this friday at 6pm in San Francisco about Reason and how to instantly start using it, http://www.meetup.com/sv-ocaml/events/231198788/
No, this is not a silly notion. But I don't think the difference Reason makes is as big as you think. I mean, I don't really believe that you can read this:
let foo = if (cond) { x } else { y };
foo + 1
but not this: let foo = if cond then x else y
in
foo + 1Not sure why the Reason syntax isn't more like F# though.
I'm finally going to switch away from my ancient nvi setup and use Atom instead! MirageOS recently moved all our libraries over to using the new PPX extension point mechanism in OCaml instead of the Camlp4 extensible grammar. This means that MirageOS libraries should be compatible with Reason out of the box -- so it'll be possible to build unikernels from a slick editor interface quite soon hopefully!
What's OCaml's status with multithreading? Are there any proposals for more flexible operators, so there doesn't need to be different operators for different numerics? (F# solves this by allowing inlined functions.)
BTW, one thing that I do find awkward about Ocaml's syntax is the difference between := and <-. Dunno if its possible to unify them in a sane manner though.
I'm also very skeptical that they make sharing code difficult. Any indentation issues will be readily apparent in a compiled language.[1] Plus I doubt this is a serious issue in the first place. And certainly it doesn't outweigh the massive gain in the main activity: reading and writing code.
1: Sure there's always a few counter examples. But in general this isn't an issue. Just like inferring function types. It's rare to have a true mistake end up changing things but simultaneously compile fine.
I know syntax is subjective, but some of the choices seem a bit odd. For example, declaring variants and using their constructors looks like Haskell, but the semantics is still OCaml. In Haskell, constructors are first order so they can be passed as functions, and partially applied. It makes sense that their declaration and use looks like function declaration and function calls. In OCaml they are not first class, that is, you can't pass the as arguments, or partially apply them. That's why it makes sense for the declaration to look like a tuple, and the use to look like a function applied to a tuple--well, somewhat, you can still argue that it's still confusing because you might expect to be able to apply the constructor to a tuple variable, but well, such is life :). Unless constructors are first class in Reason--it doesn't look like it from a quick scan through the docs--this particular syntactic difference is of dubious value, and, worse, it can be misleading to newcomers.
Also, changing `match` to `switch` seems gratuitous as well, and it also loses some of the meaning of the original. i.e. "I want to match this value against this set of patterns".
Finally, I know that using `begin` and `end` for blocks is verbose and Pascal-ish--which people seem to hate for some reason--but using { } for scopes looks out of place, and leads to awkward cases like this:
try { ... } { | Exn => ... };
I don't mean for this to sound ranty, or like I'm picking on Reason. I think it's good that facebook is tryiog to spice things up in the OCaml community.If I understand what you're saying, you provided a reason why variant arguments should not look like function application (because they have different semantics than function application), and then in the same paragraph suggested that variant arguments should have tuple syntax, while admitting that they don't actually have tuple semantics either.
The truth is that variant arguments in `Reason` actually do not have function application syntax - note the distinguishing, leading capitalized letter on the variant. Sure, they share the fact that arguments are specified via a space separated list, but function application doesn't have a monopoly on the syntactic pattern of things separated by spaces. The argument quickly breaks down.
But I guess in Reason they could be first class. All it takes is to interpret an occurrence of an n-ary constructor
Foo
as (fun a1 ... an => Foo a1 ... an) @media (min-width: 1180px) {
body:not(.no-literate) .content-root {
background-color: #fdfcfc;
-webkit-box-shadow: inset 780px 0 #fff, inset 781px 0 #e7e7e7, inset 790px 0 3px -10px rgba(0,0,0,0.05);
box-shadow: inset 780px 0 #fff, inset 781px 0 #e7e7e7, inset 790px 0 3px -10px rgba(0,0,0,0.05);
}
}
Removing it in the Firefox style editor restores normal performance.Edit: And they have commented out the box-shadow! Hah.
Checked this out, but the reason still eludes me: https://ocaml.io/w/Blog:News/A_new_Reason_for_OCaml (pun intended)
OCaml can also be compiled to JavaScript, like pretty much every language can these days.
Having worked with Reason, JavaScript, and the bridge between the two, most of my errors seem to fall on the JavaScript side. So I guess the type system's indeed working =).
But otherwise, Reason looks very cool. A nice mashup of technologies to create something that certainly looks more useful than the status quo. I hope this takes off, but I think the biggest challenge nowadays, even for good technology, is finding an audience amidst a plethora of choices. Technology, as always, is a popularity contest.
edit: Fixed now.
EDIT: and they want to use and maintain compatibility with ppx. Great news
You can even upgrade your existing OCaml source code to be in the Reason style by using the versatile `refmt` program that is included.
https://codeboard.io/projects/17520?view=2.1
Of course, you can also create your own Reason projects.
The point of the syntax toolchain is actually not to get it right on the first try but to make something viable that is easier to learn/read, avoid bike-shedding, and put all the right tooling in place so that we can very seamlessly upgrade after taking in feedback. It's pretty liberating to know you have that ability to move forward rapidly and automate all of the upgrades.
Is there any interactive functionality that your website offers that would justify extraordinary demands or does it simply display some text and images?
I agree with you but one benefit of `fun` is that it aligns better with multiples of two spaces. It's important when lists end up wrapping:
/* Nice multiple of two spaces */
fun myFun
xyz
abc => {
doSomeThings(xyz, abc);
};
/* yikes, only one horizontal space between
* doSomething and abc on the line above */
fn myFun
xyz
abc => {
doSomeThings(xyz, abc);
};
I'm obviously no stranger to bike-shedding!Jokes aside, what would your highlighting do in this case?
let (|>) x f = f x let (|>) x f = "%apply"
which utilises some language magic and is probably faster. external (|>) : 'a -> ('a -> 'b) -> 'b = "%revapply"
Also, `%apply` is usually the `@@` operator. For `|>`, one would expect `%revapply`.If they can simplify the build system to be on par with something like cargo that would be swell.
Also: having rust style traits or haskell classes would be amazing. Also macros that aren't obscure and hard to use compiler plugins please :)
Hopefully it ends up being more than just questionable sugar around ocaml and actually adds some sorely needed language features.
- Teaching new programmers how to use ML, and OCaml in particular.
- Keeping consistent formatting rules among a large team or project and automating that within your editor.
- Benefiting from the comprehensive pattern matching checks provided by the OCaml compiler.
- Benefiting from faster compile times of `ocamlc`, or faster native execution time of `ocamlopt`.
- Benefiting from Merlin, and the new version of Merlin with support for Reason - I cannot overstate how important Merlin is to my daily development.
Soon:
- Having conventions for forming namespaces within packages.
- Making it easier to share and connect many small packages into a a larger application, and develop those packages locally.
- Having "just works" support for the REPL, so that it's one fast command to start the REPL with all your dependencies loaded and autocomplete would just work.
- Having a "just works" debugger loader that maps all of your source files and compiled artifacts so you can instantly start debugging your app.
It's been a while, but taking a look at this comparison of SML and OCaml again:
http://www.mpi-sws.org/~rossberg/sml-vs-ocaml.html
It feels a bit like you've landed in some strange neither-or space for Reason? I'm not sure if it would make sense to bend OCaml into being a subset of SML or not (I know there are some differences, just not sure how much those require different syntax, or if they do) - but did you consider moving more toward SML?
I can see the reasoning between going from <> to != and <- to = (there are more programming languages, and more programmers now, than ever before, and whatever the merits of using = for comparison, almost all other languages in common use now have it as an assignment operator (even if it is still a source of bugs a la: "if(a=0) ...")).
It's exiting times with Elixir and Lisp Flavoured Erlang for Erlang, and now Reason for OCaml (and to some extent various dialects, languages and DSLs for Javascript, like typescript, coffee script and JSX for React).
Which with OCaml, is not an issue thanks to the decent type system!
I agree with you - there is something to be said for just not going against the grain where you can tolerate it. I ask myself, "Are semicolons really the hill I want to die on?".
- No IDE, I was happily using Vim but many of my coworkers were using Emacs. What helped a lot was Merlin, so I could print the types of the identifiers. This was much more useful than any REPL or IDE I have ever used.
- Debuggers: didn't use much, ocamldebug was an okay experience at best
- Linters: did not use. Most of the LOC were simple enough to just be obvious.
- Deployment: it was a Makefile which took about a minute to build the compiler from scratch. I guess that by using a proper OCaml build system we could've sped things up by requiring less recompilation but it was fine. In the end a binary fell out and could be used however.
I liked the development experience a lot, once it compiled it was reasonably clear that it would work as expected, expanding the compiler was very nice since every time I added a new variant, the compiler complained where I need to add code and then it just worked. We had the advantage that we already had our own mini standard library, so most missing utility functions were already in place when I joined.
I imagine an hlint like linter might be useful, and could give you information about common programming patterns. (Ie hlint tells you when you could be using foldr instead of an explicit recursion.)
For me, the development experience is pretty good. But it takes some time to get used to this new world. Conventions are not the same.
I think the only complains we can do at the moment are the switch from '<-' to '=' for mutable records and from '->' to '=>' for functions. But we will see how it will evolve
The comma placement suggests that developer is an adjective for experience.
- OCaml compiler's stdlib: http://kcsrk.info/reason_stdlib_docs/index.html
- Batteries: http://kcsrk.info/reason_batteries_docs/index.html
So, why do I want to learn this, rather than, say, Go or Elixir?
http://ocsigen.org/lwt/2.5.1/manual/
Also, for parallelism, elsewhere in this thread this link was shared:
Also, what's a convincing concurrency story? Does multiprogramming count?
A version of OCaml offering a similar "concurrency story" would have a lot of appeal.
But if you want POSIX threads and lightweight threads for the sake of it, then there are several lightweight threads libraries for ocaml (LWT being the most common one). POSIX threads you have to do from C though.
- Type system -> OCaml is more modern (despite being designed before Go)
- Concurrency, parallelism, garbage collector, tooling -> Go is more modern (Reason is improving the tooling with refmt for example; work is ongoing on parallelism)
I don't really see most of the changes as improvements.
Having a different, explicitly-noticeable syntax for mutable updates is nice, because it calls out mutability (which should be used sparingly).
I don't see extra braces as necessarily an improvement, given that OCaml's local scopes are already quite unambiguous thanks to "let ... in". On that note, Removing "in" and just going with semicolons removes another "smelly-code-callout" by making it less obvious what's imperative and what's functional.
I actually don't like ambiguity between type annotation and value assignment in my records. It's clear in current OCaml that {a: int} is a type declaration and {a = 1} is a value declaration/assignment. Moving to colons-for-record-values is at best a bikesheddy, backwards-incompatible change for change's sake, and at worst a breaking-change way of code less clear.
Speaking of making code less clear, how is "int list list" not clear? It's an int-list list. As in, a list of int-lists. So of course it should parse as "(int list) list". Why change to backwards annotations? Just to prevent existing code from working as-is, and making people used to reading ML spend extra brain cycles on remembering that your types read the opposite way?
And they make a huge deal out of their type for tuples being "(a, b)" instead of "(a * b)". Yeah, okay, I get it. It's not that big a deal, since people are used to reading product types as, well, products.
The other thing that seems weird to me is the need to change to a "fat arrow" instead of a "skinny arrow", again for no real reason. In fact, it just makes it more likely that you'll confuse it with a comparison operator. Nobody tries to type ">-", but people try to type ">=" all the time. You're just switching for the sake of switching, and it's not an improvement.
Their example code of their replacement for match...with is especially egregious. If you showed me the OCaml snippet and the Reason snippet unlabelled, I would think that the OCaml snippet is the new-and-improved version, since it's much more compact, much less noisy, and reads more like what it's trying to do ("match my_variable with either SomeValue x or SomeOtherValue y").
Another thing they make a lot of noise about is requiring fewer parens in some places. But then, they also require more parens in other places. So...okay? I guess? Not really a win.
And why rename equality operators? Are you really going to tell me that people prefer that their languages have "==="?
This is actually an improvement in my opinion. Reusing the syntax for function application in type application makes the language more uniform. It's even necessary with dependent types.
A lot of the better changes reminds me of the revised syntax http://caml.inria.fr/pub/docs/manual-camlp4/manual007.html
(why would you introduce the ternary operator when if-then-else is so much nicer to read?!)
It seems like Reason is solving a non-problem. When I first went to the webpage, and saw "Build Systems Rapidly", I thought maybe it was a new build system for OCaml. I was hoping it would be a Cargo-style build system/package manager for OCaml.
This is for those people who do not like OCaml because of those warts. If you are one who is already sold on OCaml, it's very easy to forget how many there really are.
Regarding "Build Systems Rapidly": Please hang in there and stay tuned. The syntax is there to help people learn ML rapidly. The Merlin integration and syntax formatting tooling is there to help people become productive rapidly inside their editors. Next, we have specified a workflow for actually building systems rapidly (as in compiling large projects with namespacing rules).
Instead of our previous approach where we just drop a more polished project with many of the goals accomplished, this kind of project benefits from expertise that is distributed across the entire industry and for that, it's better to be open earlier. I hope you can appreciate and encourage this kind of openness.
Wild guess: Due to moving to a brace syntax for blocks and '=' for assignments, they needed to move to colons to disambiguate something that already used braces and '='. That is, something like this:
let x = ref 0;
type record = { x: int };
if (cond) { x = 1 } else { x = 2 }
might read either as creating a new record value or as writing throught the reference. (Again, just a guess.)EDIT: All that said, I agree with you. OCaml's syntax is meh, but moving it closer to brace languages makes it worse, not better. Some of these changes actually move closer to Haskell (constructors without parens, yay!), and those are the changes I like.
For example, when you're using C++, be sure to rewrite the string and stream classes (like Folly does). This will ensure that you can't contribute anything back to the community, and they can't contribute to you. Be sure to use all the funny C++ features that haven't quite been standardized or supported correctly yet.
For OCaml, it's harder, since it doesn't have as many poorly designed and duplicative features. But with enough effort, you too can fix the "problem" of your code being similar to other people's code.
Documentation suggestion: add examples for string manipulation.
Edit: flambda has been released in 4.03 and I'm using it but utop is 17MB, so I doubt proper dead code elimination is part of flambda.
Edit: just doesn't load at all on Edge. Does load in Chrome/Opera and surprisingly IE 12 but doesn't load the logo's font.
| List p (List p2 (List p3 rest)) => false /* 3+ */
has the regular list destructuring in pattern match syntax been removed? that's pretty sad, if so - lists are the default data structure in ocaml, and it's worth retaining some special syntax for cons especially in pattern matches.What’s gained is that the syntax mirrors the semantics. If you have a function “f : int -> bool -> int”, then “f 5” has type “bool -> int” and “f 5 true” has type “int”. It’s not like in Forth where you can’t tell from the syntax how many arguments a function takes.
That said, I do think right-associative function application may be more intuitive—I like having it in Perl, for example.
In a language with currying semantics [(((a(b))(c))(d)] the only logical explicit syntax sugar would be LISP-like, so (v n n), (v (v2 n)). That’s imo way worse — you end up with lots of useless junk)))))))) in anything non-trivial.
At this point it's worth reminding that ML syntax was originally designed to make programs more palatable to maths students...
When so much of your code is function calls, all those commas and parenthesis start cluttering things.
Don't let my complains about syntax deter you, this looks like a very exciting project!
The paren-less function invocation has been around and tried for ages in the ML-family.
(The main downside is that variadic functions are hard to express this way. For fixed arity this is a clear win, also makes partial application nicer to read.)
Edit: The fix came quickly though.
Disclaimer: This post was written in Chrome.
In particular Rust has similar syntax, seems to have all Reason's features plus the linear types and regions/borrowing that allow memory and concurrency safety while still being able to mutate memory and not being forced to use GC.
They are aware of Rust since they cite it in their page, so I wonder why they decided to create this instead of using Rust.
It would be nice if they explained this in the FAQ.
I guess it might be useful if you have an OCaml codebase to interface with but don't already know OCaml, but given the relative obscurity of OCaml that seems a pretty narrow use (and also Facebook isn't known to make extensive use of it, afaik).
Use rust when you need the performance. Use a GC'd language like reason when you want less things to reason about.
I would say Rust trades more predictable performance for a more complicated borrow system.
The ownership model is the part that I don't myself yearning for in other languages I work in such as Python and JavaScript.
REPL is quite nice for programmer productivity.