This looks very interesting. I've always had OCaml in mind but never actually got around to using it in a project. Facebook could have done a better job describing what exactly this is, but they do provide a good overview at the end of the page (strangely!) [1].
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.
Thanks for the thoughts. I would definitely not call Reason a new language, but rather a new interface to an existing language that is already great. Not all languages make it easy to provide such an interface, but OCaml did, and the timing made sense.
I like the syntax cleanups. What's the advantage of using the existing OCaml toolchain over using an LLVM backend? Expediency and interop with Facebook's other OCaml libraries? From what I have read, the OCaml compiler only does basic optimizations and the runtime has poor multithreading support.
Facebook has many projects that are already written in OCaml, and Reason provides a path forward for seamlessly, and incrementally moving projects over to the new syntax/style.
Feel free to take a look at some Reason in the wild, used inside of the Infer project at Facebook:
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.
It's important to realise that an LLVM backend is not a panacea -- the OCaml native code generator is highly optimised for the calling conventions and OCaml GC already. LLVM's IR doesn't quite track values at the same abstraction level as OCaml so some features such as exceptions become very expensive if mapped onto LLVM without changes to the IR.
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.
LLVM may be better at generating opcodes, but a lot of things are happening between syntax and opcodes, especially type inference, type checking and inlining (including cross module and now cross functors).
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.
reason : ocaml :: lfe : erlang might be an apter comparison. it adds a new syntax parser, but not a new language. from their docs:
> 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.
I always liked ML family PLs, but my problem with OCaml is lack of good stdlib. This is why I never invested a lot of time in to it sadly. Reasons looks like a more solid out of the box ocaml distribution which I actually like a lot. Will play with it.
Glad to hear it! We've also tossed around the idea of having a precompiled standard lib come with it upon installation. We're certainly not looking to increase the number of standard libraries, when there's already so many to choose from, but including/pre-building/curating is certainly within the scope.
This would be so interesting! I don't know any other language that has made this before. But if the intention is to increase the reach of OCaml then if sound like a great plan.
I think for the most part the community is standardizing on using Core as though it was the standard. As an example: Real World OCaml, for instance, assumes Core is installed (note: I believe it is coauthored by one of the Jane Street employees).
A similar language might be Haxe, which can target C++, Java, C#, PHP, JavaScript, Python, Lua, and Neko languages, and make use of the tooling/build chain for those languages.
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...
> 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.
Ah, I forgot about Haxe. Someone correct me if I'm wrong, but isn't Haxe essentially a transpiler with its own stdlib? I think Reason is different is that it explicitly integrates into the OCaml build process.
I hope this doesn't sound like trolling, but JavaScript's syntax is now a selling point? I kinda-sorta get the reason why people want an actual JavaScript stack on the backend, but I never heard that syntax/semantics brought people from e.g. Rails to Node.
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.
I am not a fan of introducing curly brackets in a similar way I am not a fan of curly-bracketisms in F#, it makes for a clumsy noise to a relative distraction-free language like OCaml. It feels like trying to get Algol-family programmers on board, whereas OCaml users have been using ( and ) as well as begin/end since a long time.
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.
Expressions of various kinds - Async, seq, query, etc; record type "constructors"... that's all I can think of off the top of my head.
F# in general is a beautiful language though, I can't say I've ever thought about the "curly bracketisms" personally because I'm too busy being excited about how much fun it is to write over C#.
The top complain I've heard about syntax is that too many people focus on it ;-p
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!
> I don't think JavaScript's syntax is a selling point
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.
I personally think that JavaScript is one of the most meaningful and important languages that exists today. This needn't imply that JavaScript's syntax, or its semantics are to be emulated (though we're seeing a bunch of welcome improvements in recent versions of JS). The thing I like most about JavaScript is that it allows anyone, anywhere to easily deploy and share code with anyone anywhere.
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.
It's great to learn about the process. Sounds amazing. I agree that JS syntax is not a selling point, from what I read the approachability of a wider audience is. However I agree that care should be taken not to fall to easily in stripping away most of the ML interesting things and end up with everything looking the same. Go, Rust, Swift, JS it's all about the same. For different languages their "user interface" is extremely similar. I think that with your proposals you have shown a great suitability to discover the balance between being different and being accesible, I don't think they have to be opposed as many language designers seem to be convinced.
I for one welcome the syntax. I run the OCaml meetup in Silicon Valley and syntax is definitely an issue for newcomers. This makes it easier for other programmers to instantly just jump into OCaml/ML rather than ask about what is `in` or what is `let foo = function`, etc etc.
This definitely makes me feel more warmly toward OCaml. Syntax has kept me away in the past. It's silly, but it's really hard to evaluate a language if you can't read the examples.
People like to say that syntax doesn't matter and over the long term maybe it doesn't but anything that detracts from learning a language does matter and sometimes syntax is exactly that needless barrier.
IMHO `let in` has more to do with semantics than syntax. `let a = b;` doesn’t mean the same as `let a = b in …`. It’s like `def` vs. `let` in Clojure. Outside of this specific case I agree OCaml doesn’t have an easy syntax; I have to re-learn some parts of it every time I need to write in that language.
> It's silly, but it's really hard to evaluate a language if you can't read the examples.
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:
I've heard that said, but I don't see how it's a big deal. OK, the very first example introducing let bindings would have to come with a sentence like "the 'in' part of 'let ... in' means 'in' just like in English: 'let' the binding be valid 'in' what follows". You don't have to define a whole new syntax where a single sentence in a language tutorial might be enough.
But I admit that I probably can't fully appreciate whether this is really difficult for someone used to JavaScript.
Except when you're in the top level - in which case you don't use `in`. Oh, and don't forget all the nuance of interleaving imperative commands. I'm an experienced OCaml dev and this trips me up (the "ml compared" section of the docs lists some common pitfalls that Reason resolves).
Of course, once you know what 'in' means, it's easy to read, but you have to learn it, and get used to it. I've teached programming to students in finance, and this learnt me how much I underestimated the impact small things like that can have on the learning curve (and the motivation).
Hmm, the new if syntax really feels like a step backwards. (But I can see why they chose it: the C-like syntax here isn't too much of a burden, and is familiar to a lot of programmers already.)
Wonder if this project has anything to do with Eric Lippert's move to Facebook (https://ericlippert.com/2016/02/08/facebook/ - Eric has also been producing a series of blog posts implementing a Z-Machine interpreter in OCaml to run mini-Zork on, starting here: https://ericlippert.com/2016/02/01/west-of-house/). Eric was on the C# compiler team at Microsoft and previously worked on JScript.
damn, i recently started writing a z machine interpreter in ocaml, and now i both really want to read those posts and really don't want to be influenced by lippert's design decisions before i've at least gotten my own project solidly underway.
It's always better to know about the design decisions others have taken. If they faced the same choices you did, you can know their view on the tradeoffs (and experiences with their choice) and choose the same way as they did or choose differently, but either way you make your choice with a little more knowledge. If they come up with an idea you didn't even think of, surely you want to know about it, even if you aren't actually going to use it.
if i were doing it as something intended for serious use, i'd definitely want to see how lippert did it. but the point of doing this (other than the whole rite-of-passage aspect of writing a z machine :)) is the challenge of designing and implementing it from scratch, and hopefully as cleanly and compactly as possible. if i read lippert's blog and he came up with an idea i didn't think of after i had already solved it some other, potentially worse way, i'd be delighted to see that it could be done better. if i see his solution to some piece that i haven't even implemented yet it would just tempt me to simply adopt his solution.
Similar to the point that I'm sure it is a subconscious plagiarism. In other words, the person who created the logo had seen Reason magazine's and unintentionally channeled it when creating the new one.
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!
The Atom Reason plugin uses Nuclide's system for error rendering (in the diagnostics bar), and type hints. But the actual logic for integrating with Merlin has been completely rewritten in Reason itself, and compiled from Reason into JS to run as an Atom plugin. So there are still merlin features missing because the Atom plugin is relatively young, but if you want to help us implement the missing features, it can be a fun way to try Reason itself (compiling to JS).
I started off a bit skeptical with the <- renaming to =. Mutability should be rare enough that <- makes things stand out. But apart from that I think I rather like this syntax, on the whole. Not a fan of semicolons. It also makes me appreciate F#'s #light syntax (now its default). Using whitespace really clarifies stuff, and there's always in and ; for fallback.
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.)
I suspect the syntax of `<-` (or lack thereof) will be a common topic of discussion. Let's see how various audiences respond to this change and then discuss if we'd like to restore `<-` for mutation. Personally, I don't use a ton of mutations in my code so I have less at stake and if there's anything we can do to appeal to a wider audience, I'm inclined to give it a shot.
Maybe I'm too used to Ocaml to comment but I think using `=` for mutation is a bit misleading because it might make it appear that `x.mutablefield = bla` and `let x = bla` are the same thing, which is the case for typical imperative languages (but definitely not for Ocaml).
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.
F# doesn't unify them, but it makes := largely redundant by letting you do "let mutable ...", and then assign to it with "<-" - so you simply don't need to use refs if you just need some mutable data (you still need them if you want to have a closure mutate something it closed over).
`ref` and `mutable` were unified in F# 4.0. You no longer need to use a `ref` when closing over a mutable value, you can use `let mutable` in all cases and the compiler will figure it out for you. The generated code is the same as before, it's just that there's a unified syntax now.
There is an optional warning one can enable which emits when a `let mutable` is converted to a `ref` behind the scenes - for those who want to by hyper-aware of hidden allocations.
If there is one single thing from F# I would like to have in OCaml it is the whitespace syntax. I can write nice OCaml, but I often need to exploit corners in the grammar and cheating around with precedence and @@ to get my code to not be full of clumsy parens, anonymous functions etc.
I loved so much significant whitespaces when I discovered them in Python! Since then, a few years have passed, and I've come to the conclusion that significant whitespaces are a mistake: they make automatic code formatting difficult or impossible (gofmt, refmt, etc.), they make sharing code snippets by chat or email error prone, they make automated code generation error prone too. Please don't add them.
This is not correct. You can still auto format just fine. It won't change indentation obviously, since that would change the meaning of the program. What problems do you have in mind?
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.
You're right about auto-formatting being possible with significant whitespaces... but:
When you copy-paste a block of code in another block of code, with significant whitespace you have to correctly reindenting everything very carefully, while with explicit blocks you can let an automatic formatter do the work.
When you copy-paste a block of code in chat/email/comment, it is sometimes difficult to preserve significant whitespaces. For example, I've seen a lot of blog comments "eat" the white spaces at the beginning of each line (example: https://unspecified.wordpress.com/2011/10/18/why-pythons-whi...)
It can be difficult to fix code incorrectly mixing spaces and tabs (especially for beginners).
Rob Pike wrote on this topic:
> Some observers objected to Go's C-like block structure with braces, preferring the use of spaces for indentation, in the style of Python or Haskell. However, we have had extensive experience tracking down build and test failures caused by cross-language builds where a Python snippet embedded in another language, for instance through a SWIG invocation, is subtly and invisibly broken by a change in the indentation of the surrounding code. Our position is therefore that, although spaces for indentation is nice for small programs, it doesn't scale well, and the bigger and more heterogeneous the code base, the more trouble it can cause. It is better to forgo convenience for safety and dependability, so Go has brace-bounded blocks.
Without examples it's hard to say. Python isn't static, and it's type system isn't as capable as MLs.
I'm entirely unconcerned about random formatting systems destroying whitespace. Some eat angle brackets. Maybe I'm not copy+pasting enough. I find "for beginners" to not be useful as a measure of anything - anything can be said to be confusing for beginners. But I can see how people might come to a different opinion.
Haskell doesn't nearly has as much of a problem with copy-and-pasting from websites as Python have. (But in Haskell the significant indentation is much more optional.)
> When you copy-paste a block of code in another block of code, with significant whitespace you have to correctly reindenting everything very carefully, while with explicit blocks you can let an automatic formatter do the work.
I've heard this argument a lot, but how often does it happen to copy paste extensive parts from web sites? Some short bits, yes, but longer parts with blocks? Almost never, since I always have to rewrite them to fit my variable names etc, so might as well make sure the formatting is right.
Nice to see that OCaml is getting so much love at facebook. Unfortunately, adding a new syntax that's almost OCaml, but not quite, doesn't seem like such a great idea. While it might make the language accessible to more people, it runs the risk of fragmenting the community.
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.
> 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
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.
I didn't say constructor arguments don't have tuple semantics :). In OCaml tuples are a "unit", i.e. you can't use (,) as an operator. In that sense they match with the constructor semantics: it needs all its arguments at once. It's the constructors not being functions that I was complaining about. Also, I'd say that capitalisation alone is not enough to compensate for constructors looking like they're curried functions. But that's just a matter of taste.
> 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.
But I guess in Reason they could be first class. All it takes is to interpret an occurrence of an n-ary constructor
I've been dealing with this lag in firefox for the past 6 or 7 years. It's hilarious to me that they still haven't fixed it. Just one of the reasons I've been extremely negative on firefox.
This is the first time I've seen something like this. I use Firefox full time for development and personal use and do a lot of front-end work. ¯\_(ツ)_/¯
Think of Reason like "CoffeeScript for OCaml"—a nicer surface syntax for the same underlying language. With CoffeeScript, it's a nicer JS. With Reason, it's a nicer OCaml.
OCaml can also be compiled to JavaScript, like pretty much every language can these days.
it's a really well-thought-out set of improvements to the ocaml syntax, done by people who actually seem to appreciate MLish syntax for the most part (rather than trying to get it to look more like C for its own sake, a la mythryl)
It plugs into the existing OCaml compiler toolchain [1], which is quite smart. So it's basically an interface to OCaml that shares the stability and features of the OCaml compiler and runtime.
Thought it was mostly summed up in the first paragraph... "Reason is a new approachable interface to the OCaml language, with the long-term goal of improving the developer experience by providing a functional syntax and toolchain for writing, building and sharing code quickly and easily."
Looks like their plan is to reuse the ocaml compiler backends that output javascript; but it doesn't sound like they're doing anything explicit to promote Reason -> Javascript compilation.
Well, if you ignore the red button that runs you through comparisons of different Javascript syntax to the equivalent Reason syntax, then sure, they aren't doing anything explicit...
Whether they have an intermediate step that is OCaml or not is irrelevant. Most compilers have one of more intermediate representations between source and executable. I think providing a syntax comparison to Javascript right next to a syntax comparison to OCaml is a clear indication that they are marketing to Javascript programmers, and the only reason for that is if they intend thelanguage as a replacement or supplement to Javascript.
That may or may not seem relevant to you based on ciniglio comment, but I think it's on point if you follow the thread from it's source down.
In 2016, "marketing to JavaScript programmers" is pretty much the same thing as "marketing to programmers". Providing context that the vast majority of programmers will understand is helpful regardless of the compilation strategy. That being said, of course people want a language that can compile to JavaScript, and it's worth mentioning the expanding set of options for doing so. But the syntax comparison really would be worthwhile even if it weren't the case, if only to provide context to what is likely the largest developer community that exists today.
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.
For now, that's somewhat accurate. If you check out the JS comparison page, you might say it looks like JS with OCaml's influence.
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.
Sounds like FF can't handle gifs, but Chrome/Safari do a good job. I've disabled the gif on the main page just to be friendly to FF while I figure out a better approach. Thanks for the report.
I can run the Unreal engine, use google maps but not view your website. I'm not convinced Firefox is at fault here.
Is there any interactive functionality that your website offers that would justify extraordinary demands or does it simply display some text and images?
It turns out it was the drop shadows, and only were an issue in Firefox. I don't know what to make of the fact that we can run Unreal but we can't render drop shadows performantly. Maybe we should build web pages using WebGL.
Normally the easy answer is to turn off Javascript, but in this case it makes the whole thing completely fail to render. For a site that's just showing you some text.
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);
};
It would make the function name stand out from the parameters. Again, to pick one unintuitive abbrevation, just because it's a 3-letter one like let, it's just not serious! Make all be 3:
type -> typ
switch -> swi
if -> iff
else -> els
in -> inn
downto -> dow
module -> mod
Call you language 3-letter reason. You see how it ridiculous it gets? You can't make all keywords be 3-letter and if people care about alignment, they can further align, but most don't care as much as you think!
It doesn't have to be three letters, keywords can be odd numbers and achieve a similar effect - also, we likely will use the `mod` keyword instead of `module` fwiw.
That would be another poor choice as "mod" is used as "modulo" - there's no need to abbreviate "long" words like "module", because they are not used so often and bringing ugliness and confusion just to save a couple of characters per file is not worthy!
In this case, you don't even need the "fun" keyword as syntax-wise, "=>" alone can be used like in other languages as (parameter1, parameter2) => parameter1 + parameter2, for example - it's obvious enough without having to prefix with anything!
Anyway, I see that you want to be "different" in hopes to be "better", but, indeed, you're just "weird", instead.
"+." for float addition, "^" for concatenation, etc.
"(" <val> ":" <type> ")" instead of the shorter and more readable <val> "as" <type>.
For example, why did you choose "mutable" and not "mut"? See, your language is full of inconsistencies, it's not well-thought, it's not intuitive! For example, you chose "rec", which usually means "record" for "recursive"! In your "for"-loop, you have just "to", not "upto", but then "downto"! A good choice borrowed by some old languages would be to use the optional "by" <step>, which defaults to +1, but in a case of a "downto", would be -1, and thus giving you a more powerful loop!
You don't know of any other languages that use `mod` to represent "module"? Say, perhaps, the one you just advocated for in another thread?
And there are in fact issues with using x => y syntax for lambdas without a leading fun/fn keyword:
let x =
(this,
is,
a,
really,
long,
thing
) => 10;
- In that example it's not possible to tell if the leading ( is the start of a pattern for the sake of lambda, or a tuple. This happens with ES6 today as well (destructured record argument). It's not just a matter of human readability, it's a matter of building an efficient parser.
- The (x : y) syntax for type annotations is not new or weird to many people. That's the syntax used by ML, OCaml, and JS (Flow).
- We're likely going to swap some operators for string concat, so that it would be the more common ++ operator.
- The rest of the observations are good and we should address them soon.
How about building functional operating systems and unikernels: https://mirage.io/. Since Reason is fully compatible with OCaml, you can build your own Reason unikernels on top of MirageOS libraries. Here is a list of mirage OS pioneer projects: https://github.com/mirage/mirage-www/wiki/Pioneer-Projects
At risk of being pedantic, that's actually shorter. It also doesn't work, at least on the version of OCaml I'm familiar with. In order to invoke that particular bit of "language magic", you'd have to declare it external and explicitly give its type:
Try out the OASIS build system. It's very similar to Cargo/Cabal (although it's separate from the package manager) in that you basically declare what you're working with and it does all the building for you. It's super simple to use and is good enough for 95% of use cases.
As for traits/type classes, this is in development with the modular-implicits (experimental) fork of the compiler. It's highly likely that some form of this will make it into the language soon, but for now you can already start playing around with it if you want. It's super cool because it uses the module system to express type classes/traits rather than adding more parts to the language.
- 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.
Interesting project. Ever since being exposed to a bit of Standard ML (which never had much of a "real-world" standard library, as far as I could figure out), I always wanted to like OCaml, but couldn't quite get over the odd syntax.
It's been a while, but taking a look at this comparison of SML and OCaml again:
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).
> 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) ...")).
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?".
What cheng said, but we could also make sure that the syntax for modular implicits plays very nicely with the rest of the grammar. With Reason we can rethink the grammar holistically instead of having to find room in it for new features. The hard part is in the actualy implementation of Modular Implicits, but that's currently being handled by skilled professionals and Reason will be able to use them.
Yes, I'd describe it as being "non-invasive". It means we get the benefit of literally every feature implemented in the core of the language (multicore, F-lambda, modular implicits, ppx attributes), but can decouple the process of deliberating over how this is presented to the user, and (not to beat a dead horse) but we don't even have to worry about getting it right on the first try! Now that I've embraced this as the new "normal" way, I couldn't imagine having to design a syntax and stress over having to determining the exact permanent concrete syntax that needs to live virtually forever without knowing which other language features will be added later.
I was working on a 30kloc compiler written in OCaml:
- 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.
> - Linters: did not use. Most of the LOC were simple enough to just be obvious.
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.)
I haven't done anything ≥10k lines yet, but I do have a few projects between 1k and 5k lines that I've been working on and I've easily written 50k+ lines of OCaml in the past year. The development experience I've had is probably the best I've dealt with so far. There isn't a ton of infrastructure around the language, but everything that exists feels very high quality.There's no standard IDE really (although I did recently find OCamlEditor, which seems very nice and even runs on Windows!), but Merlin basically turns any compatible text editor into a full-fledged OCaml IDE (with features like quick-checking code, auto completion, linting, and automatic indentation/formatting). Honestly, debugging isn't something I've had to think of very often. The type system does a really good job of rejecting buggy programs, so whenever I write code it usually works as intended immediately (or I've made a small mistake that I'll notice pretty quickly).
I know the Haxe compiler is written in Ocaml, and that's a decent size open source project. I believe Facebook uses it for a number of their programming language related tools too. It seems to gave a sweet spot for writing language parsers and compilers.
See the FAQ, as this is a fairly anticipated question. There's some benefits to having some token to separate let bindings and statements, so that the grammar is unambiguous, and it doesn't matter too much which token is used (monkey emoji anyone?) However, I think it may be possible to eliminate delimiters altogether eventually. Because we have the `refmt` program which can convert and beautify between two arbitrary versions of the syntax, we'll be able to automatically upgrade your code if we do find a way to eliminate delimiters unambiguously. Stay tuned.
It would be good to look at the F# spec for a description of their existing indentation & semicolon elision rules. In practice I’ve found them nice to work with, although they sometimes require excessive indentation.
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
There is the small standard library that ships with the compiler. And then there are more extensive ones such as Batteries and Core. It is easy to generate docs in Reason syntax from OCaml projects using `redoc` tool. Here is Reason docs for:
So, I know OCaml is impressively fast. And, I know OCaml is impressively terse ("concise" may be a more positive term). But, I wonder what would make one choose OCaml (or a variant of it like this) over some of the other new or old languages that exhibit some excellent characteristics for modern systems. In particular, a convincing concurrency story seems mandatory. I don't know enough to know if OCaml (or this variant) has a convincing concurrency story, and nothing on the front page of website tells me.
So, why do I want to learn this, rather than, say, Go or Elixir?
A convincing concurrency story is the one offered by the two languages you mentioned: Go (with memory sharing, which is an advantage or a drawback depending on your goals), and Elixir (no memory sharing between lightweight processes).
A version of OCaml offering a similar "concurrency story" would have a lot of appeal.
Those are just techniques, other techniques achieve the same goal, such as multiprogramming, which I think is better that's why I asked.
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.
Yes and no, depending on which aspect of the language you consider:
- 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)
As far as I know, there is nothing fancy about it, except for the fact that a lot of work has been put into Go's garbage collector, especially in versions 1.5 and 1.6, with people working full-time on it.
Go easily achieves GC latencies well below 10 ms, even for programs using a large heap, without having to manually "tune" the GC.
As excited as I was to see a big new thing in OCaml-land, I have to say my excitement died down as I read on.
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 "==="?
> 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?
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.
Yeah, I kinda feel like this whole project is pointless. As many warts as OCaml's syntax has, for the most part I actually like it.
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.
"As many warts as OCaml's syntax has, for the most part I actually like it."
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.
To start, we have "fixed" type parameter application syntax. (Most people see this as a win and now matches Haskell IIRC). Some have requested ability for type annotation ayntax to be above the value it annotates.
By the way, do you even need to work towards _one_ better syntax? Seems like you should be able to support mostly whatever syntax the user wants? (Within reason.)
> 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.
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.
It's important to use an incompatible dialect of every language and toolchain that your company uses. If you just use the vanilla project, the company might be tempted to adopt outside open source projects rather than reinventing the wheel in-house. This would be a terrible thing because it Wasn't Invented Here (tm). Also, new college graduates might not be appropriately awed by the pile of High Tech Stuff you show them on day 1, if just anyone else could use it outside the company.
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.
It would be nice if they'll make it work on Windows platforms. There is already an issue for that[1]. It also depends from the Windows support in OCaml itself and opam[2].
Reason looks interesting. I have had a 5 year run of alternating between really liking Haskell, and sometime thinking that my own development process was too slow using Haskell. I am putting Reason on my try-it list.
Documentation suggestion: add examples for string manipulation.
Sorry, what I meant is that I remember having read somewhere that dead code elimination, or some sort of, will be one of the optimization coming in the future due to the introduction of flambda. When I go back home I will try to find a reference, I might recall wrongly
You're probably right that it was mentioned on Jane Street's blog that flambda will enable such optimizations. I recall one of the ocamlc devs saying that real dead code elimination is planned but not available yet.
Is Facebook using mirage or similar ocaml unikernel tool chain? Is part of the goal of reason to make a more approachable syntax available for authoring code that will run inside next-generation containers?
From what I can gather, it should work independently from the Mirage toolchain, but will remain compatible with all current OCaml tooling, so using Mirage tools will work as well.
| 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.
Thanks for the feedback. We can change it to `Cons`, but I was assuming that anyone who knew what `Cons` was, would know what `List` meant, but not everyone who understood what `List` meant, would know/recall what `Cons` meant.
The difference between curried langs like OCaml and Haskell and languages like Ruby and Elixir are that the leaving out of parens actually means something, ie. all functions take one argument. If you wanted parens whilst maintaining the same semantics, you would end up having to do write: `add(2)(3)`
Indeed, but leaving out the parens makes more work for humans. What does `a b c` mean? `a(b)(c)`? `a(b(c))`? If the only thing that is gained by leaving out the parens is brevity, I don't think its worth it.
It’s no different than having to know the associativity of an operator. Does “a - b - c” mean “(a - b) - c” or “a - (b - c)”? The former, for no reason other than a long history of convention. Same goes for function application. And you could make the same argument about languages that require parentheses for function calls: what does “a(b)(c)” mean? “(a(b))(c)” or “a((b)(c))”?
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.
But it’s not `a b c`. Rather it’s something like `verb noun noun`. Which is much less ambiguous.
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.
Please take a look at the FAQ which describes the best way to move forward with evolving the syntax. It helps to know your personal technical background and where you're coming from, as well.
I do like your idea, but you can currently use parens - it's just that they aren't required by the parser when the argument is clearly one item (like an integer constant etc). Then at that point, it's just a matter of configuring the source formatter to always include them.
My background is in Python, Scala, Java, C, and Ruby. My reaction is based on the monstrous DSLs I've seen in Scala and Ruby (because the language lets them), where the clever syntax actually hid the important features of the interface. Every time you get to "wait what is this actually doing" and you have to learn another tiny language instead of just writing functions that return a `Future[HttpResponse]` and be done with it.
Don't let my complains about syntax deter you, this looks like a very exciting project!
That's a valid complaint for new untested syntax that people came up with yesterday.
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.)
if this had come out five years ago i'd probably be all over it, but i think i'd rather just use rust at this point. different syntax but better safety and it's not like the ocaml ecosystem has a lot to offer
This page is completely unusable due to lag. From the other comments it seems this is FF specific. One would think FB would have the resources to test new pages at least on common browsers before publishing.
Thanks for finding that out. We (Firefox) fixed a box shadow performance bug [1] in Firefox 47, which will be released on June 7th. It looks like this site is hitting that perf bug.
Completed nuked FF for me and for what its worth it doesn't even load in Edge. Just throws up a "This page is having a problem loading" page. Works fine in IE 11...
It seems to me that Rust would be pretty much strictly better than this.
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).
Actually, OCaml has plenty of features that Rust doesn't have. The ML module system/functors are a big one. Polymorphic variants. Global type inference. GADTs. Garbage collector :).
Rust’s borrow system is actually not the key part; if it were just that, then yes, it would be purely a complication performance would be the only important part about it when comparing it with garbage collection. No: the key part is the ownership model, that an object is owned in precisely one location. Borrowing sits on top of and fits into that, not the other way round.
The ownership model is the part that I don't myself yearning for in other languages I work in such as Python and JavaScript.
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.
[1]: http://facebook.github.io/reason/#how-reason-works
[2]: https://github.com/facebook/reason