BuckleScript: write JavaScript faster, safer and smaller
bloomberg.github.io
bloomberg.github.io
Large JS output even for a simple program
"In BuckleScript, a Hello world program generates 20 bytes JS code instead of 50K bytes. This is due to the fact that ... all BuckleScript’s runtime is written in OCaml itself so that these runtime libraries are only needed when user actually call it."
What happens when you go beyond Hello World though? Surely there's some overhead vs. plain JS. For example, Hello World in Scala.js is tiny, but once you touch, say, the Scala collections library, then file size increases significantly. In the end, once you go beyond trivial applications, there's a 150KB baseline tax to pay for using the full power of Scala in the browser.
If BuckleScript provides an OCaml-like language with file sizes comparable to plain JS that is both compelling and impressive.
[1] http://bloomberg.github.io/bucklescript/Manual.html#_problem...
Sounds like Reason can run the show as well (OCaml's crufty syntax has always bothered the SML'er in me), going to give this a look.
I do not think this is what makes the 150 KB tax of Scala.js, though. The dead code elimination of Scala.js is really good, plus we combine it with Closure as well. But it faces a very difficult challenge: the entanglement of the Scala standard library. The collection library was designed when the JVM was the only target, and decoupling within the collections library was definitely not in the requirement set. This is why, once you touch the Scala collections library in Scala.js, you receive 150 KB worth of (non-gzipped) code. There is currently a large-scale effort to redesign the collections library for Scala 2.13 [1], with, among others, a desire to reduce inter-dependencies (while keeping most of user-level compatibility). This should hopefully significantly improve the situation of Scala.js regarding code size for smallish applications, as you will only pay for the collections you actually use; not the entire set of collections once you require one of them.
Java is the greatest and worst part of Scala.
Without Java, the language would be far, far less popular than Haskell. With Java, it has a lot of forced compatibilities, e.g. null.
Are you implying that Scala.js didn't work out? That would be denying the huge success it has within the Scala community. It is notably supported by most major Scala libraries. To back this by data, it appears 5th in a ranking of Maven artifacts based on the number of artifacts depending on it [1]. Above it are Scala itself, Specs2, Akka and scoverage.
Scala/.NET didn't work out because we never managed to reconcile the type system of Scala with that of the CLR. For JavaScript, we did manage that, and pretty easily: it's much easier to erase all types than converting from an advanced type system to another advanced type system.
[1] https://scaladex.scala-lang.org/search?q=&page=1&sort=depend...
Er, definitely not. Bad mis-statement on my part. Should have said "also had challenges." And you're correct about type erasure.
Scala/Scala.js/SBT are my tools of choice for web apps.
I gave a talk "Scale your code with Scala.js" at Fluent last year https://conferences.oreilly.com/fluent/fl-ca-2016/public/sch...
I had completely misunderstood your earlier comment ;)
Bucklescript: 16K
Haste (Haskell): 36K
ClojureScript: 144K
It's worth noting the Clojue version is the furthest along, and the Bucklescript version is the least, but all do some ffi and list manipulation. I did some simple tests with ghcjs, but it was producing files over 1m even for simple "Hello World" type code (I think because it includes the entire Haskell threaded runtime), so I didn't go very far with it.
Elm (type inference) is sort of. While there is a lot of OS type projects used, having bloomberg use it is a plus. Interesting that FB have build system ^Reason^ (build system) doing something similar (OCaml backend->JS) ~ http://facebook.github.io/reason/
Bloomberg and Facebook are two big users of BuckleScript. FB have a couple of folks writing significant stuff in Reason, compiling with BuckleScript, and deploying to user-facing web properties.
I only saw rather simple typing examples, which didn't seem much different from what TypeScript can do.
On the other hand I read often that ocaml doesn't have runtime errors, which I certainly get with TypeScript.
Of course the rest of the book is a great read too if you're so inclined.
It replaces a lot of the idiosyncratic bits of OCaml's syntax with things that feel more appropriate if you're comfortable with other modern languages.
A quick example is tuple types. OCaml declares tuple types as int * int, which makes total sense if you know that tuples are a product type. However, you actually create tuples using commas. Reason throws away the connection to theory and uses the same syntax for types (int, int) and creating values of that type (3, 7).
Happy to answer any questions I didn't get to in the talk as well!
I think the tooling isn't available for transforming Reason => JSX in a consistent development environment from what I gather, but I haven't paid attention for a few months.
Dart has a large team behind it, an awesome package management infrastructure, a "Dart native" angular 2 library.
One reason to define a tool and use language clearly, I interpreted, 'Build Systems Rapidly' as a ^build system^ where in reality Reason is a ^systems language^ to build things quickly.
Some of the tools are fantastic. I would love to have REFMT "dynamically as the window resizes in order to make optimal use of screen real estate while still abiding perfectly by the formatting rules" built into language editors to aid development.
I've been using Coffeescript in projects for about two years. I know people have raised issues with it vs ES6, but I still really like Coffeescript. I feels more natural with my Scala/Ruby background and it outputs into Javascript in ways that (mostly) make sense and are predictable.
You can learn F# with dotnet core, which has a better ecosystem for web development. OCaml is quite poor in that domain.
https://github.com/fable-compiler/Fable/blob/master/README.m...
There's a newer branch called Fable Arch which I believe is focused on promoting the Elm Architecture for structuring web apps:
https://github.com/fable-compiler/fable-arch
FunScript is another alternative:
There are several active projects and bindings that you can take a look at there: https://github.com/fable-compiler
"Database access from a Suave.IO app isn't any different from database access from any other .NET / F# app you write."
Any way you like, really.
But removing delimiters in my opinion does not help readability. Most time is spent reading, not writing. It's similar to claiming more efficiency by removing lanes and signaling from a highway...
Then, whitespace has more meaning than it should in CoffeeScript, and inconsistent indentation is possible, whereas in Python/Ruby it is not without an error. Therefore a formatter can break your code.
Snippets/templates/autocompletion can save the work of typing delimiters. Delimiters can be enforced with CoffeeLint, but then that's optional, it is more work, and it is a friction point with people that do not see value in formatting.
CoffeeScript does not have a lot of tooling around it, and the community has moved on.
There are documentation tools like docco and codo, but there is no tooling that makes it as well integrated with the language as JavaScript + JSDoc, where there is tooling that can verify types, function parameters and return types giving you a lot of static analysis power.
Then, the entire point of a scripting language is not having to compile. With CoffeeScript you lose that advantage to some extent, and the compiler does not filter many errors, making it a bad tradeoff.
By turning it into a more readable Js, I wonder if the debugger would play more nicely too. I've noticed in Scalajs the debugger randomly misses breakpoints or moves to the wrong line sometimes. Anyway not a rant on Scalajs, I do like it but there's definitely some bottlenecks for me.
By contrast, reading BuckleScript's output JS is a breeze. No name mangling, idiomatic style, sensible code flow.
I agree with your analysis on breakpoints and step-by-step in Scala.js. Usually it's a good idea to disable the Scala.js optimizer if you're doing that, using:
scalaJSOptimizerOptions ~= { _.withDisableOptimizer(true) }
But it's still not 100% perfect. I am toying with the idea that we should have a mode of the optimizer that tries to optimize for debuggability with step-by-step and breakpoints. This would try to arrange the generated source in closer relation with the source code (like, 1 line = 1 line). All of this is trying to work around limitations of source maps, and also of browsers' support for source maps. It would be so much easier if source maps were a little bit more powerful in what they can express (e.g., indicating what a "step" should be in the code).This would allow me to write GWT-style client/server apps where both ends are written in the same language with a set of common library code compiled for both, right? What's the library support like? Don't suppose there's any ELM-style DOM diffing support, is there?
Exactly, client side/ server side in a single language. People are working on porting the Elm architecture to BuckleScript, they will be coming soon
https://marketplace.visualstudio.com/items?itemName=hackwaly...
My opinion on the matter is that Javascript sucks. We all know it sucks too, which is why things like Elm, CoffeeScript, ClojureScript, TypeScript, BuckleScript, Scala.js, etc. exist. We want to fix Javascript because we understand that it sucks; therefore, we tend to embrace these various attempts to make it less stupid. The solution to the problem, in my mind, isn't yet another Javascript transpiler though, but rather native support for superior languages.
I'd like to see an API built into browsers to make them language agnostic. I think that would go a long way towards making web programming less lame. It may also give us a chance to clean up the DOM.
Haskell compiled to C for the longest time (and quite a few other compilers use that trick). That didn't make Haskell a bandaid around C, did it?
Or lots of examples here - https://github.com/OvermindDL1/bucklescript-testing
Might still be rough around the edges, but it will improve soon enough.
BuckleScript is fast, and compiles to readable JavaScript.
Please don’t just go spouting that Rust is the answer to everything; it’s not. It’s also not always relevant in a discussion.
(I say this as someone who is lauding Rust at every turn and who has been using it seriously for years and who is looking forward to a solid wasm target and ecosystem.)
To me, in the WebASM world, transpiling to JavaScript is starting to seem a little old-fashioned. Readable JavaScript is not as important as long as we have source maps, which WebASM was designed to take into account. Presumably Rust (or Ocaml) compiled to WebASM will also have substantially improved performance compared to transpiled JavaScript, which IMO is worth the longer compile cycles.
I think Rust is relevant because Ocaml and Rust share a lot of heritage (indeed, I think Ocaml was one of the most influential languages in the Rust design), so I think that makes it relevant in this discussion.
Compiling a language like BuckleScript to wasm is therefore not possible at the moment, simply because the interop features of BuckleScript cannot be encoded in wasm.
Besides, there are other difficulties: wasm doesn't have any kind of managed heap at the moment, which means that compiling a managed language to wasm requires to embed an entire GC in your production code! It's much better to take advantage of all the VM features offered to JS, like a GC, when compiling a managed language to the Web platform.
It's behind a flag in a couple browsers. Even with a flag, if you're going to actually do anything with the DOM, you're going to be shipping a js support library and calling into it. Using something that works now has value, particularly when you could get wasm in the future off the same code if anybody writes an OCaml wasm backend.
> Presumably Rust (or Ocaml) compiled to WebASM will also have substantially improved performance compared to transpiled JavaScript
Bucklescript adds asm.js type hints (but not the use strings) to the js output and does a fair number of optimization passes. Aside from reducing parse time, going from its current output to wasm is unlikely to pick up much in the way of perf. I'm actually not even convinced that wasm is going to be that much faster for load+parse over an optimized js payload because asm.js/wasm have to ship the runtime (allocator, stdlib, etc) while js just has to ship the code.
> Readable JavaScript is not as important as long as we have source maps
I write Clojurescript full time, which has source map support. I completely disagree with this statement.
> Ocaml and Rust share a lot of heritage
Rust was bootstrapped off an OCaml compiler. I like Rust and advocate for it but bringing up another compile-to-js language, particularly one as nascent as Rust doesn't really have anything to do with the merits or drawbacks of Bucklescript.
What is the obsession with having readable JavaScript? In the debugger (devtools) I don't want to step through the low-level assembler instructions (JavaScript), I want to remain in the high-level language where reasoning about the behaviour is actually possible. We have sourcemaps for a reason, make use of it!
Do you really want to drown the interesting HN comments in a heap of "hey, my favorite language also compiles to JS" kind of comments?