Become a Creator today!Start creating today - Share your story with the world!
Start for free
00:00:00
00:00:01
The State of Full-Stack OCaml (with António Monteiro) image

The State of Full-Stack OCaml (with António Monteiro)

Developer Voices
Avatar
3k Plays2 months ago

OCaml has one of the best-loved compilers available, and parts of it are surprisingly pluggable, so it’s not surprising that someone would eventually try to wed OCaml with JavaScript and the web browser. In fact, the ecosystem has gone further, and there are now a bevvy of options for people who want to write OCaml and run it in the browser, or want to write OCaml in the browser, or want to write something that looks like JavaScript but runs OCaml on the backend.

Joining me to explore the OCaml-meets-JavaScript world is Antonio Montiero. He’s a key maintainer/contributor for Melange and ReasonML, as well as several other interesting OCaml web projects.

We kick off by discussing the benefits of OCaml and how it clicked with him personally, before we dive into how and why the compiler is being adapted and tweaked to take it to a whole new audience of web-hungry developers.

Support Developer Voices on Patreon: https://patreon.com/DeveloperVoices

Support Developer Voices on YouTube: https://www.youtube.com/@developervoices/join

Sponsor Antonio’s Work: https://github.com/sponsors/anmonteiro/

The OCaml Platform: https://ocaml.org/platform

OCaml on Discord: https://discuss.ocaml.org/t/ocaml-discord-server/1884

ReasonML: https://reasonml.github.io/en/

What is Melange? https://melange.re/v4.0.0/what-is-melange.html

Melange for React Devs: https://react-book.melange.re/

The Melange Playground: https://melange.re/v4.0.0/playground/

js_of_ocaml: https://github.com/ocsigen/js_of_ocaml

FUN OCaml Conference: https://fun-ocaml.com/

Kris on Mastodon: http://mastodon.social/@krisajenkins

Kris on LinkedIn: https://www.linkedin.com/in/krisjenkins/

Kris on Twitter: https://twitter.com/krisajenkins

Recommended
Transcript

Introduction to OCaml's New Capabilities

00:00:01
Speaker
This week we're looking at the OCaml compiler and extending the reach of that compiler, because whilst OCaml has always been a backend language, it's got its site set on your browser too.

Guest Introduction: Antonio Monteiro

00:00:13
Speaker
I'm joined for this by Antonio Monteiro, who's been doing a lot of interesting, sophisticated compiler work to help OCaml grow out into the world of JavaScript.
00:00:23
Speaker
but also to help coke some existing JavaScript developers into the functional world of OCaml. And he's doing that by extending OCaml's compiler on two different fronts. First, he's the creator of Melange, which will let you write OCaml and have it produce JavaScript.
00:00:41
Speaker
And second, he's a major contributor to Reason ML, which lets you write something that looks an awful lot like JavaScript, but emits type safe backend native OCaml.

Why Use OCaml for Browser Environments?

00:00:53
Speaker
Now, of course, the first question is, why? Why would you want to do that? What's so great about OCaml that we should put it in the browser? And what does Antonio find so great about it? What's his personal reason for all this work? But the most juicier question is, how's it done?
00:01:10
Speaker
How do you compile and transpile between two different languages? Because, obviously, parsing for loop syntax in one language and emitting a different for loop syntax, obviously that's trivial. But how do you handle the major differences, like different concurrency models? Or how do you port OCaml's first-class module system to the JavaScript world?
00:01:34
Speaker
To answer those questions, we need to start picking the brains of an

Antonio's Journey with OCaml and ReasonML

00:01:38
Speaker
expert. So I'm your host, Chris Jenkins. This is Developer Voices, and today's voice is Antonio Monteiro.
00:01:58
Speaker
Joining me today is Antonio Monteiro. Antonio, how are you? Pretty good. How's it going? Very well, very well. yeah You're going to take me into a world I don't offer. In fact, I've never visited. I've just skirted past the coastline of which is Oak Hamill. Very excited.
00:02:16
Speaker
you and We're going to have to go through a big list of Oak Hamill projects you're involved in, but it's fair to say you're up to your neck in Oak Hamill, right? I'd say that. I think i think it's been then you know, like maybe like TCP, like a slow start and then and yeah, really fast catch up. So what's your what's your origin story? What lured you in? um Yeah, I think I first got my contact with OCaml in college. So this would have been probably all about like 13 to 15 years ago. And
00:02:57
Speaker
There was a class in and the n OCaml. i i sort of like It was very different from all the languages that we had been learning it up until that point. And then um I kind of liked it, but then I put it aside because and but all we had to do was implement some some like kind of class project ah that was very self-contained. I didn't see the value in the real world. And so it wasn't until, I think, 2016, when I saw ReasonML actually on Hacker News,
00:03:27
Speaker
ah that I sort of and look at look at it again. um so So I saw the Project Reason ML um announced by Jordan Walk, who also created ReactJS at Facebook. And the name sounded familiar. He's like, oh, I've i've heard this word OCaml before. like why aren't they you know Why are they putting a new face on it? Or why does it need it? And what can I do with it? um and I decided to do you know take it for a spin. And honestly, it was very a very rough experience. It was ah really, really like rough rough to to get started, to get installed. The ecosystem wasn't there. The build tooling wasn't there. um Really, really yeah hard to get started with, um which I'd say is I'd understand why not a lot of people use it at at that point.

OCaml's Strengths and Ecosystem

00:04:26
Speaker
but then I kept playing with it and I kept understanding the the language concepts. I, I joined some community, the scores and slacks. I got some help, uh, different ways of installing, uh, tried different tooling and eventually clicked. And the, the, I'd say the reason why I, I keep using OCaml today is for all it's, uh, it's yeah for all its merits, right? Uh, so it, it has a very,
00:04:54
Speaker
ergonomic type system. um It infers a very good type inference based on Hindland Miller. It has, a I'd say, a wide community these days. The module system is great. um And even if you can't find, it's honestly hard to explain because it's such a familiar feeling when when when you try to camel
00:05:24
Speaker
a program that you can define in like types and and like what they call algebraic data types, basically. um and you can sort of derive your program from the types that you defined. Everything compiles, and then you have a working program. It's sort of like a magical feeling, a good like dopamine injection that ah really sort of like, I don't know, I'd say like keeps you going and keeps you like writing more and and and trying more things with the language. Even if you don't have a library that
00:06:00
Speaker
can be like that exists for for a particular use case that you have in

Evolution from BuckleScript to Rescript

00:06:05
Speaker
OCaml. It has a very good like FFI, foreign function interface story, to C, for example. So you can always model your you program as if with some like and link against some some C library, for example, or C++, plus plus or or even Rust these days. And and so you can can call between one and the other.
00:06:25
Speaker
Okay. this This actually reminds me, there's a lot of overlap between that and my story with Haskell. And I guess it's like which of those two languages your university teaches you as the weird functional language. That's right. Was there a particular was there a particular moment when the penny dropped with OCaml? Was there something that slipped into place and you understood it?
00:06:53
Speaker
I think we'd have to go back to the Bucklescript project. This was a project I think started at Bloomberg that the goal was to compile OCaml and ReasonML to JavaScript. When I got started with OCaml, I think that's that would have been the most polished workflow at the time for people like me who hadn't used OCaml before and didn't know a lot about um like compiling like for context like I had been a JVM JavaScript ah like JavaScript and a JVM programmer because I used closure extensively and my experience was interpreted languages.
00:07:37
Speaker
um I had only done a little bit of C, C++ plus plus in college um using um probably a make file, something like that. So coming coming to like a compile language in the workflow there was sort of ah a bit different to me, um especially like some like I had also used like Golang before, but like everything in Golang is super well integrated um with like one single command. ah In the case of OCaml, everything felt a bit spread out. Everything felt a bit fragmented in in some case in some sense. And Bucklescript was really trying to unify this ah experience together. This was something that they were heavily working on, even inside Facebook. I think at some point, messenger dot.com was written
00:08:24
Speaker
I think the stat was like 50% was written with ReasonML and compiled with BuckleScript. So that's, I think, where i where it clicked for me. I i tried BuckleScript. It was an NPM install away. I could see OCaml, several OCaml modules. this This sounds really trivial today with the tooling that we've gotten, but I think at the time,
00:08:50
Speaker
it wasn't right there It wasn't necessarily there and definitely it was not for me, but just the ability to put together a few libraries, a few modules, work and get like a working JavaScript program was really what clicked for me. And then from then on, like my entire quest was having the same experience in native programs.
00:09:14
Speaker
yeah Yeah, something about the language. like If you can compile it, it works, provided you can get the flipping toolchain to give you the same experience. right So you mentioned Bucklescript. Now, I'm coming as an outsider, not really understanding the OCaml ecosystem. but You've got Reason ML, which is a syntactic front end, and BuckleScript, which is a compilation back end. BuckleScript might be a defunct project or a rebranded project or?

ReasonML and OCaml in JavaScript Ecosystem

00:09:46
Speaker
Yeah, I can, I can give you a rundown. Give you a lay of the land. Absolutely. Yeah. So what really, what I really got started with was Reason ML, uh, from seeing it on Hacker News and I decided to try the language. Um,
00:10:02
Speaker
I think to say take a step back, right OCaml is an umbrella word, I'd say, for many things. um it's We can start by the OCaml compiler, which is this tool chain that allows you to take OCaml, the syntax, and compile it into native programs and run them, or bytecode programs, because it has to like the compiler actually has ships with two backends.
00:10:27
Speaker
Like write a bytecode virtual machine and a compiler that compiles programs to native assembly. The thing about OCaml is very pluggable, especially on the compiler front end. And when I'm saying compiler front end, I mean the syntax, the preprocessor extensions. Right. And what ReasonML still is, is basically just taking the surface syntax and replacing it with something else. So instead of writing ah like the OCaml language, you write ReasonML, which is a language that is more closely familiar to people who've used like ALGOL syntax before. It looks a lot like JavaScript or C um or Rust or Go. Yeah.
00:11:16
Speaker
the The default for familiar to programmers syntax. Exactly. What yeah everyone sort of learns these days, or at least is familiar with at at some point. This is this this is what ReasonML is. It's just just a ah different syntax altogether for OCaml. OK. Buckle script.
00:11:35
Speaker
Or or let's let's take another step back, which is let's go to the compiler back end now. right um I mentioned that the OCaml compiler ships with a bytecode virtual machine and the ability to compile programs to native assembly.
00:11:51
Speaker
there the there' there are all there are also tooling There's also tooling to take some kind of intermediate representation that the compiler produces and compile that to JavaScript.
00:12:05
Speaker
Okay. The first one that ever existed, ah to my knowledge, is is a tool called JS of OCaml. And JS of OCaml takes um the OCaml bytecode produced, the same bytecode produced by the bytecode virtual, like the that is interpreted by the bytecode virtual machine, interprets that bytecode at compile time and produces

Decision to Fork BuckleScript into Melange

00:12:27
Speaker
JavaScript that you can run on the web or wherever JavaScript runs.
00:12:32
Speaker
Okay, yeah, I can see that. Right. um We can go into advantages and trade-offs later, um but just to give this keep giving you the lay of the land, what BuckleScript did was hook into an earlier compiler intermediate representation that is ah That looks a lot more like the lambda calculus, if if you're familiar with that. OK, yeah. So we're in AST and a couple of steps down, presumably? Exactly. So yeah so the I would say the the order would be something like syntax, which would be OCamlou or reason.
00:13:12
Speaker
um abstract syntax tree, and then type inference, like in the type checking algorithm runs, you you you augment this abstract syntax tree with a typed abstract syntax tree, right, a type tree, at which point you you have all the information, the all the static information that you're you're you're ever going to have about your program, so you just throw all the types away when generating the lambda intermediate representation.
00:13:40
Speaker
Right. Yeah. Right. So the the lambda part of OCaml doesn't have any types. they're They're thrown away between type checking and and like lambda generation, let's say. um but But it does have a lot more information than the the bytecode intermediate representation, which is why BuckleScript then chose to hook into this earlier intermediate representation, the lambda, rather than the the bytecode. OK.
00:14:07
Speaker
To answer your other question, why BuckleScript is a defunct project, um I think around 2020, there was this sort of ah ah rebrand into, I'd say mostly for marketing efforts, um where the people behind BuckleScript wanted to take the project into a different direction, where which was really like a break from from OCaml. um but And and what what happened was Bucklescript renamed to so to Rescript, which is a language you've might've heard as well. um So rescriptlang dot.org, it's a great language. It's like sort of the the the the natural successor to Bucklescript in some sense. um It is though like by not OCaml at all,
00:14:59
Speaker
even even Even if it's built in OCaml and has some historical like precedence there, it is a different language that combines to JavaScript and a lot of people are using it. It's no longer just a final compilation phase. It is entirely its own separate thing.
00:15:21
Speaker
Exactly. i'd say i um I think I'm not as familiar with it these days as I could be, but ah to my understanding, it it sort of hooks into the same intermediate representation. It still is backed by the OCaml compiler. It's basically like a fork of the OCaml compiler that produces JavaScript. But it ah it it made a whole like different whole different choice like a whole different set of choices. it made it um
00:15:52
Speaker
Yeah, I took the project and I'd say a different direction. and And I'd say the major thing that they've shipped recently is the removal effectively of currying or partial application. Okay. ah One thing, so like OCaml is ah You mentioned you're familiar with Haskell, and Haskell obviously has this too. Every OCaml function, just like every Haskell function, is automatically queried. And what I mean by that is if you have a function of three arguments to a a return result, you can decide to apply only one argument, at which point you get a function of two arguments to the result.
00:16:32
Speaker
right
00:16:34
Speaker
And this is something that works really well in languages like OCaml or Haskell. But the maintainers of Rescript, I think, decided that when you're compiling to JavaScript, it's more familiar if you if you have functions as they exist in that environment as well. And so there are I believe they are now uncurried by default. And so that's that's a big break, for example, for from OCaml programs.
00:17:03
Speaker
Okay. thats That feels like, as an industry, we're not quite ready for that holy war. like It's maybe 10 years away before everybody has an opinion on whether it's good or bad. That's a fair point. But for now, you're giving me the impression that the OCaml compiler chain is very pluggable. It is. Yeah? So yeah is that well-architected and designed to be taken in pieces?

Melange's Role in JavaScript Environments

00:17:30
Speaker
I don't know about that one. ah okay i think I don't know if I'm the best person to make that judgment either. I know it's it is very pluggable in the sense that, at least for from a like a syntax perspective, as I described, you can sort of switch syntaxes.
00:17:46
Speaker
as um yeah There's also another part that people would be familiar with as macros. In OCaml, they're called PPX, or pre-processor extensions. And what kind of macros are we talking?
00:18:00
Speaker
These are AST level macros. so like okay yeah They are... The good kind. etc not Exactly. I guess not the not like not not like C preprocessor macros, for example, but more like... also ah Well, I guess also not really Rust level macros because I think those are defined in a different way. I'm not too familiar with those. I know they take AST as well and transform it in some sort of way.
00:18:30
Speaker
But in OCaml, this is sounding like Lisp-style macros. ah
00:18:37
Speaker
Yeah, I guess Lisp-style macros would probably be a fair comparison here, even though Lisp is you know obviously like homo-iconic and untyped, and probably a lot easier to manipulate the AST than in something like OCaml, where the AST is very much like like um an algebraic data type. right um And so it has many, many variants or enums or or or or cases. right yeah And the surface area is quite large. And and so writing writing a macro or a PPX in OCaml is not always straightforward because of that.
00:19:22
Speaker
because you have to decide which language construct, right which syntax construct you want to hook into. You need you want to mode modify that, produce it and a new version of... um ah that like that syntax node. right And also, you don't really have access to typed information about the program. You can't really query other parts of the brooke program in the default case right for for macros, because they just work at the syntax level.
00:19:51
Speaker
yeah yeah so says and sorry I was as just going to mention, I mentioned like that this part, yes, they they're very pluggable, and there are libraries to to help you with that.
00:20:05
Speaker
But the other parts um I don't think are as pluggable. So for example, if you if you want to hook into the bytecode, I believe that works because it's like the final output of a program when you're compiling two bytecode. But if you want to hook into like the type tree or if you want to hook into the the lambda representation, I think at that point you'll find that you're you're going to be writing a compiler fork.
00:20:31
Speaker
Right. Okay. So that does lead into one of your big projects, which this is, you have done this, right? You've, you've hooked into creating a different compiler backend. that'sre melan Yes. Uh, so I mentioned previously how a buckle script sort of broke away from OCaml in a sense to create re-script. I was personally very,
00:20:58
Speaker
into the OCaml part of the ecosystem and wasn't quite ready to let that go. okay um At that point, and I think this would have been probably almost four years ago to the day, um I forked BuckleScript before it became Rescript. And I know and know this is confusing. So to just to reiterate again, um as BuckleScript, which compiled OCaml and Reason ML to JS, became Rescript length, this new language um that wanted to take both of syntax and compilation and in a new direction, I kind of wanted to stay with but the BuckleScript
00:21:47
Speaker
ideology of things, if if you will, wrong yeah which which to me is more naturally closer to OCaml than what came after, right? So we fought BuckleScript and wanted to to keep working on it and keep making it better for the OCaml community. Another way to look at this would be if you're um someone who writes JS for a living, for example, like you you're a JavaScript developer. yeah um You're familiar with the entire ecosystem. You like to install things from NPM. You'd probably go with Rescript these days because Rescript is an NPM install way and you can try
00:22:35
Speaker
a new compile to JS language in your own programs. However, if you're a NoCaml programmer and you want to produce you're very familiar with NoCaml and its ecosystem, you want to produce JS that is not only modern, but also amenable to being parsed and transformed by all the modern tooling and in the NPM world.
00:23:02
Speaker
This is where you you'd use Melange, this the project that I started. Right, so the so the broad division is, are you a JavaScript programmer wanting to get closer to OCaml or an OCaml programmer wanting to get out to the browser? that's Yeah, that's I think so. rough Yeah, I think that's a very fair statement. Okay, so what does a tool chain for the average OCaml programmer wanting to be in the browser look like?
00:23:32
Speaker
Yeah, um so Melange works very similarly to how Bucklescript used to work as well.
00:23:43
Speaker
However, one thing that we did we did change is how it interacts with the rest of the OCaml platform. And I think this is the biggest selling aspect for Melange, one of the biggest these days. The way Melange works is at the compiler level, right? It can take any syntax, it can take any abstract syntax tree, just like the OCaml compiler. It and also hooks into this, like the Lambda intermediate representation and then produces beautiful and beautifully readable JavaScript from there. right At the ecosystem and platform level,
00:24:21
Speaker
And this is a big difference from how BuckleScript used to work back in the day. Melange is integrated with it with what what we call the OCaml platform. And this is the official term that um represents an entire set of tooling that is designed to work around the OCaml compiler and ecosystem. okay The OCaml platform has tooling to build your code, to obtain packages,
00:24:49
Speaker
to get editor integration in your editor. So like the language server protocol and such.

Integrating OCaml for Full-Stack Development

00:24:55
Speaker
okay yeah yeah It has tooling for automatic documentation generation and probably a few others that I'm i'm spacing out on ah right now.
00:25:08
Speaker
Yeah, but all that stuff that... I think it's some of the stuff that actually makes writing a language hard. Because there you are, you finished writing your language, you packed yourself on the back and you still got to write a package manager and a build tool and all that stuff, right? yeah Yeah, exactly. And so this was a very much intentional and very early design choice that we wanted to sort of like go back to the roots. We want to go back as close as possible to OCaml because if we were able to integrate with the OCaml platform, if we were able to integrate with Dune, the OCaml build system, then we'd have access to the entire ecosystem. to all like we it We'd effectively be standing on the shoulders of giants with all like all the tooling that had been designed and planned and and written before we came along.
00:25:57
Speaker
Right. And you get back to that experience you had where BuckleScript was the first thing where the tool chain seemed to work for you. In sort of a different way. Yeah, but yeah, like and now we sort of go back to the roots and to the OCaml ecosystem. Okay. um So Melange uses Dune to build your projects, which is the OCaml tool. As an aside, is this an OCaml theme that we have to do? Frank Herbert puns.
00:26:24
Speaker
this ah It might be. okay like ah this is i can't I can't take any credit for this, honestly. I'm not into the the Dune lore, but ah and a a community like member came up with the word melange and I thought it fit very nicely.
00:26:45
Speaker
Also because melange is a word in French that means mixture. And melange is a mixture of a bunch of different tooling coming together to produce JavaScript from OCaml. So I thought it was was perfectly fitting and and and I ran ah away with it.
00:27:02
Speaker
um I was saying that Melange builds your projects with Dune, the OCaml build tool. okay you You get your packages, your libraries from Opam, the OCaml package manager.
00:27:15
Speaker
It uses the OCaml LSP, the OCaml Language Server Protocol, and Merlin, which is a previous tool. The the library that provides all like the the type completion and and and information and diagnostics to to the OCaml LSP. It uses ODOC to produce documentation. um and you can Oh, the other one that I forgot earlier is there's this tool called Dune Release, which you can use to package and publish your melange projects to Opam, the OCaml package manager. um I'll actually be talking in September in Berlin about a melange of tooling coming together at a new conference called Fun OCaml. Oh, nice. Yeah, so pretty excited about that. and
00:28:04
Speaker
i'll get to maybe reiterate a little bit of what we're talking here and present knowledge in sort of like this unified way of all the tooling coming together. This is my thing, think, right? So I can think of maybe two, maybe now three languages where I'd have a genuinely good experience if I want to write web stuff where the front end and the back end share code. Yes. And I'm going to pick PureScript, which is niche, but I love it. Gleam, which is new, but has a very nice kind of overall ecosystem. Can I add OCaml now to my, to my list of, this is genuinely browser to server.
00:28:49
Speaker
This is a goal. um This is definitely a goal. I'd also add closure and closure script in that mix um as um it's very much designed to to do that. And I've done that a ton. We've done that at the previous jobs. It works really, really, we really well together too.
00:29:06
Speaker
um But sort of like sort of to go, yeah, go back on topic. And like I guess you'd use PureScript with Haskell. Is that your same experience? No, it's so it's all compiling down to Node.
00:29:20
Speaker
So JavaScript in the front-end, Node in the back-end, and it's all ah the surface syntax is all Haskell, but the actual implementation is basically a JavaScript engine. Is that also what you were thinking with Gleam? or Because I think Gleam also has different back-ends, right? I think they can compile to the... Yeah, they can compile to JavaScript or to the Beam, which is the Erlang virtual machine. not yeah I was actually thinking and more in terms of... because Okay, this is this might sound a bit a eliite elitist, but um that is like JavaScript to JavaScript is the easy mode, I think.
00:29:56
Speaker
okay right ah where Even these days, right you can you can write JavaScript or TypeScript and have your front end and your back end in TypeScript or JavaScript. Just like you mentioned, you can have pure script compiling down to Node and JavaScript on the front end. I think what I but i and envisioned when when you talked about this was sort of like totally different runtimes running the same language, communicating with each other. And that's where ClosureScript compiles to JavaScript. Closure runs on the JVM. yeah
00:30:29
Speaker
Right, yeah, I see. Similarly with OCaml, and this is what i I think I meant as is a goal, is you can have OCaml compiled through Melange to JavaScript. And again, like I'd say the easy mode then would be Melange compiled to Node.js on your server, which also works. But what we're really working on and we're sort of excited about is also having the same code base with at least like parts that are shared, right? um Hopefully, you'd want your types mostly to be shared between the backend and the frontend, so you can serialize and deserialize easily. Where a part of it compiles to JavaScript with Malange, but then your backend compiles with OCaml to native code, and you you sort of can run the same code base and communicate ah with one another.

Technical Challenges in Compilation

00:31:25
Speaker
Do you end up with like, how does that play out? Do you end up with parts of the code marked as if I'm compiling as JavaScript do this? That's exactly right. Yeah. So it's yeah like language directives.
00:31:38
Speaker
Yeah, those don't really exist, and sort of that that that's sort of one of the things that we're working on. ah We think we can make it work with ah preprocessor extensions, PPX, um right because they're basically extensions to the language where we can add those directives or we and with some support from the build system.
00:31:59
Speaker
So this is very much a work in progress, but one of the exciting things that Ahrefs are doing um and Ahrefs have been from the beginning a major sponsor to Melange and still are to this day. So I thought I'd mention them together ah today as well. They're like this big like search engine optimization company um in the space and what they they develop all their apps with OCaml. All their front end is compiled with Melange.
00:32:30
Speaker
the thing that okay The thing that they're doing recently is they're basically re-implementing the ReactJS server-side rendering in OCaml. They're implementing the new React server components, which is effectively just ah an RPC protocol in OCaml. And so they've they've gotten to this point where, I mean, this is not only a goal, but already a reality in some sense, where some of the Ahrefs web pages and the the web applications like when they get to your browser. like Before React.js compiled through Melange takes over, there has been a server-side rendering process that took the same code that renders on the front end.
00:33:22
Speaker
um but Well, I guess, yeah, it is another interpreter, right? like It compiles it to HTML and sends that over the wire to to the browser. Okay, so this is the thing where like the code might run in the browser and generate HTML, or you might send JavaScript over the wire and it runs and creates HTML in my browser, or you might run it locally on the server and just send the HTML part.
00:33:47
Speaker
That's exactly right. yeah yeah And I'd say it sends the HTML part. It also sends to JavaScript. But React.js just takes over and um installs event handlers, for example, on the JavaScript that is already on the page and compatible to what it would generate. And this is called hydration. Right. Save me some thinking. Why is that a good thing? The the reason why this is a good thing um is because historically, and I'm not really sure what the state of that today, um but I'd say it's still, I think it's still sub par, but historically, like,
00:34:26
Speaker
crawling engines, they did not run your ja the JavaScript on the web page. So if you have a world where every web application is written with ReactJS, the first thing that you get whenever you load a HTML for a website is you get a container div that loads a script right with a script tag. Yeah.
00:34:48
Speaker
Whereas in this world, the first thing that you get is you got to like the full HTML page and then the script tag that takes over and like installs the event handlers. So you can imagine how this for for a search engine optimization company feels like a very important topic. Yeah, yeah i've I've definitely been involved in a project in the dim and distant past where we had to serve up a static HTML version of the page for crawlers, just so they wouldn't list this as basically empty pages.
00:35:18
Speaker
Exactly. Yes. Yeah, that makes sense. That's exactly the problem that it solves. And does this solve the problem that, um, but then as a developer, I don't want to think about that. And I just want to have the whole thing look like I'm writing react. Yeah. Yeah. Okay. That's right. The other, I mean, the other problem that it solves is is also like, in terms of like some, some loading metrics, right? Um, I think, was it FCP first contentful paint or something like that? Um, where, ah um,
00:35:46
Speaker
if If you send HTML to a browser your your page won't seem like it's loading for forever or for some time because you already have the structure there and then the the the JavaScript can can take over. Whereas in the other case, you sort of you're incurring the the downloading of the JavaScript, the parsing of the JavaScript by the engine, and then the execution of React.js and like the HTML, the DOM generation on the front end. It's sort of like a hack. You skip all of that and then you just you're still doing all those steps, but you already have some content on the page that your users might be reading.
00:36:27
Speaker
Yeah, yeah, then if I can send the user or the HTML up front, I buy myself an extra second of loading time while they're looking at it. For example, yes. ya Yeah, yeah, yeah, yeah, OK. OK, that makes sense. So I see how that whole ecosystem fits together. What makes the job of writing ah ah OCaml internal representation to JavaScript execution engine hard?
00:36:57
Speaker
How different are they? ah yeah what is what sorry what is the so I'm just thinking about how you implement this. You're there good at the something that looks like a lambda calculus with maybe a bit of extra information in inside the OCaml compiler. Now you need to write JavaScript.
00:37:19
Speaker
That doesn't sound too, it sounds like a large job, but not necessarily a difficult job. Is that right? So what what makes, I guess, generating JavaScript from this Lambda representation hard? yeah There are a few things. um I think in the in the best case, it isn't a very hard transformation.
00:37:44
Speaker
um the if if If you're just taking the the like but core OCaml language, the lambda is already pretty i'd say optimized for code generation. So you have like so a lot of deduplication already done. You have um a lot of references already resolved. You get a lot of information from the lambda. There are some things that you don't get.
00:38:11
Speaker
um And one example would be how the OCaml memory model is a bit different than how a JavaScript program would look like. One example of that would be if you have a record. And the record is just a fancy word for like a dictionary where the keys are static um at compile time. yeah Right. um we we Ideally, we would want to generate a JavaScript object from a record in OCaml.
00:38:43
Speaker
Right. Yeah. Makes sense. It's you know, key value pairs.
00:38:48
Speaker
The thing that we had to to change, because the OCaml compiler elides between type checking and and lambda generation, for example, is we had to preserve some information about what the keys are named. Because in the in the OCaml memory model, if you have a record and you have access to the type, say that you have properties A, B, and C, they are laid out in order in memory. right So youll you'll know that the first block is A, the second block is B, and the third block is C.
00:39:17
Speaker
Right, so there's no need to keep the names around. There's no need to keep the the key names around. Exactly. So this is something that, because we're yeah we're not doing source to machine transformation anymore, we're now doing source to source. And when you're doing source to source, there's a lot of information that you need to preserve that is otherwise not available when you're doing source to machine transformation.
00:39:41
Speaker
That's sort of like one of the the early
00:39:46
Speaker
barriers that we ran into. ah There are some more related to, for example, I mentioned how the core language is sort of easy to compile. But what I was alluding to there is that there there's all these extensions to the OCaml language, and it's not clear how you compile those. For example, the module system where the module system is in OCaml, and maybe just to make an aside here, is is really, really interesting. where Every file is a module. okay And you can think of a module as just a bag of values. right So every file, just like in other languages, right they export a set of values. This is, I think, pretty straightforward to comprehend. So most of those values being names which point to functions. Or, yeah, functions or values. or
00:40:42
Speaker
The cool thing is that every module can have sub-modules.
00:40:47
Speaker
okay right So modules can have bags of values themselves. So you can have a module ah file called a dot.ml that has a module b inside it. And b is another collection of these values.
00:41:03
Speaker
and They are sort of interchangeable in the sense that one is a file, but you can treat it as a module because it's a first class citizen in the language. And while the module system is, and I call this while the module language is sort of different from the value language in OCaml.
00:41:26
Speaker
you can sort of convert between one or the other, and you can like pass modules around as arguments to functions. like You can sort of lift them and unlift them as and in that sense. So give me an example of a function you would run on a module. Yeah. So say that you have, for example, a
00:41:53
Speaker
I guess the first example that comes to mind is is like ah an asynchronous runtime, right? It's an asynchronous runtime that you can think has the same signature, but it can have different implementations. So like one, you can have you can vary the backends. And in I think OOP terms, this would be the strategy pattern, not to not not to bring up the gang of four.
00:42:19
Speaker
ah But you done for you so you'd start by so by writing a module signature. And in in this case, it'd be something like, what is the type of a like a future in this runtime? And what is the type for the function bind if we're doing it like in if we're doing it in like a monadic term, for example?
00:42:46
Speaker
right um so A type would be a type T that you can that can of remain anonymous and bind would be the usual like you know T to a function that takes an A, produces a B of T or a T of B, right and then um the result is also like a T of B. This is the function that allows us to chain a series of futures together. Exactly. Right. This would be, or or otherwise, a monadic bind that is and And so say that you want to you want to pass a this monad signature around, and you want to implement it in different ways. um We're talking about it in asynchronous runtime, but this is really way more generalizable than that, as you probably know. So you basically define a function that takes a module having this signature.
00:43:34
Speaker
And in every call site, you can just define your own module implementation and pass that first-class module, that's how they're called in the language, to these functions. um And so... So do I get to say, give me any... Sorry, one more just one more thing. like to Inside the function then, um what you would do is you would use the bind function from the module that you got as argument.
00:44:03
Speaker
Okay. So I can say, give me any module that implements this batch of functions. And I can start using it as long as you obey the contract for a module. I don't care who's implemented it. It's a's great like it's a bit like a collection, a bit like an interface. Yes.
00:44:24
Speaker
it's ah It's a bit like an interface. And you can implement this. like You can ask me, like, Antonio, why why why so complicated? right you Can you just pass a record around? The answer is yes, sort of, in some cases. Sometimes it's easier to abstract with um with a module. OK. It depends on whether or like, ah it depends on polymorphism, which we we're not going to get into.
00:44:53
Speaker
okay So this, um, this is a challenge for compiling to JavaScript. Some of these. but Yeah. Like, I guess the, where we started was before, yeah, before the, the, the big tangent on the Okelo module system, which I recommend everyone to go and try and give it, give it a try. Um, some of these language extensions are more problematic than others to, to compile.
00:45:22
Speaker
but One example is, but honestly, for modules, JavaScript makes it very easy ah because if you squint, they sort of have the same representation where a JavaScript module that you import, at least in the common JS paradigm, right is an object with is a bag of values, right? It's an object with key value pairs where keys are the names and the values are the values. Yeah. Yeah, okay. So we we decided, okay, if we compile, you know, sub-modules, right, modules that exist within a file to a JavaScript object of the same shape, we can pass them and interchangeably.
00:46:08
Speaker
Yeah, so in ah and a project like this, the the trick is to start figuring out what the thing in OCaml is like in JavaScript. This is this is a big um challenge, and this is a big part of it, for sure. Where, you know, how does a representation of a value in this language map to the representation?
00:46:32
Speaker
to a a And I guess the like the choices are always like, does it map to like a readable, an ergonomic version like version of a structure that people in like JavaScript are familiar with that we that is also performant and that we can manipulate easily through code generation? Right.
00:47:00
Speaker
But has that been always possible? Or have you had to say, look, we're just not going to support this OCaml feature, or we're just not going to emit particularly ah idiomatic code? Yeah. that that's it's Well, I guess the answer is no. It it hasn't always been possible. okay There are some features, especially recently in the OCaml compilers that we don't so don't currently support. So OCaml 5, which was the the most recent big release of the OCaml compiler, for example, introduced two things, two major things. One is shared memory parallelism. The other one is algebraic effect handlers. okay yeah As you can imagine, JavaScript being a single-threaded language, we can't really support the multi-core nature of of of ocamp the the new OCaml runtime.
00:47:59
Speaker
Yeah, I can see that being... So that's that's a pretty big limitation. The other one is is effect handlers, which is something that is currently under research. It's something that we think we might be able to support, ah but we haven't been able to do it so far. I think... Yeah, to to give you a a bit more detail,
00:48:23
Speaker
The way fact handlers work is they effectively unwind the the like the call stack and they sort of like, I think implementation wise in the OCaml backend, they're really doing like stack switching, like Golang does for for their runtime. Okay, I'm not familiar with that.
00:48:41
Speaker
where
00:48:45
Speaker
So if you think about exceptions, for example, right? um Effect handlers, I think, are effectively resumable exceptions in the sense that you can throw something, which unwinds the call stack. rate But then after you're done doing the that operation, you couldn't go back and to where you were before. Right. Yeah. Right. And so there are a few ways, I think, to do this. One of them is stack switching. The other one is sort of like calling with continuations. Yeah.
00:49:16
Speaker
And so those those are pretty big challenges for us in Melange. The first one being that we can't really do stack switching in JavaScript because we don't have that level of access. there is no like There's no go-tos, there's no jumps that you can can really do. Yeah. And the second one is this could probably be implemented with like a continuation passing style or something like that.
00:49:40
Speaker
However, that would require us to add a new like say like a new argument to every function that you defined when generating JavaScript code.
00:49:51
Speaker
Yeah. And this breaks a pretty big assumption, a pretty big like contract in how Melange compiles your code to JavaScript these days, which is that the calling convention is the same between OCaml and JavaScript. So you can you can synallyly syntactically look at a function, let A that takes arguments B and C,
00:50:16
Speaker
And you can guarantee that you can you can call that function from JavaScript by calling A with arguments B and C. Ah, so it's not just that I want the output code to look readable. It's that I want to be able to use it as though... This is another... Yeah, like I can carry my intuition across from the OCaml code to calling it from JavaScript. yeah And we want to preserve that as much as possible. Yeah, yeah were switching everything to continuation passing would totally destroy that.
00:50:44
Speaker
Absolutely. Yeah, exactly. And that leads us to, I'd say maybe like yet another challenge of how to implement a compiler from OCaml to JavaScript, which is how do you handle the boundary, right? And the boundary is always the sort of the most interesting part, right? When does the OCaml end and when does the JavaScript start? when like How do you call Libraries that exist in the NPM ecosystem, they are exclusively written in JavaScript from your OCaml program that compiles to JavaScript. And how do you do you know and vice versa, right how do how do you compile something with Malange that you can call from your like from JavaScript? right sort of how I think the and the the analogy for native here would be you know
00:51:33
Speaker
thinking of Malange producing a a dynamic or a static library that then you link against, right? And some other artifact. Yeah, I might want to go and publish a package on NPM for JavaScript developers, but I don't really want to write it in JavaScript.
00:51:50
Speaker
Exactly. you You'd want to write it in OCaml. You want to run it through Melange. You want to publish to NPM and tell everyone, hey, here's how you call this this package from JavaScript. Yeah. And I don't want to ever admit that I wrote it in my favorite language. That's right. yeah So this is this is ah this is another challenge where we talked a little bit about currying before. And currying is a pretty big challenge and and for for these cases. And that is something that We can do some compiler optimizations during the compilation phase, but we can't really do that for for all the cases, especially like all the dynamic cases where functions are passed around with each other. So Curing does actually need to have a runtime when you're compiling Malange to JavaScript, or yeah, OCaml to JavaScript with Malange.
00:52:46
Speaker
Okay. So hang on. if i got I haven't quite got this. So in OCaml, there is native carrying and you need to create an extra runtime in JavaScript land we do to handle that.
00:52:59
Speaker
think think of um a list map, for example, where you're you know mapping over every every element of the list. of a list yeah So the signature of list map in OCaml is you know you as function, list, and result. right yeah um But you can you can choose to, and this is very common in in functional programs, you can choose to partially apply the list map function to right just pass it the first argument, which is the callback.
00:53:29
Speaker
and you And now you have a function that is a reusable function that can take any list and apply that transformation to any list. yeah yeah right How do you express this in JavaScript? Because in JavaScript, list map would be a function of two arguments, right a callback and a list, to or and like a new list. And if you just pass one argument,
00:53:58
Speaker
The function is fully applied and the second argument is undefined. Yeah. Yeah. So you end up with this pattern where you write out like, I'm a function that takes two arguments. No, I'm a function that takes one argument and then returns a new function that's going to wait for the next argument. If you want to do that in JavaScript, lab it depends you end up reinviting reinventing, reinventing, carrying. Yes. Yeah.
00:54:21
Speaker
It depends. As I mentioned before, right like we try to to do but like the full full application as much as possible, especially if we if we can figure it out at compile time, because that ends up being more performant than applying one argument and then getting a function and applying that argument again. yeah But we can't do this for all cases, which is why we also ship a runtime that you don't never have to worry about, but in some cases, Malange generates
00:54:49
Speaker
calls to this like curry runtime that that handles this for you. OK. Yeah, because I would have thought it's almost impossible in the general case to recapture what the uncurried function was in the original source code.

OCaml to WebAssembly Potential

00:55:07
Speaker
I mean, think yeah it depends. It's the unofficial motto of the podcast. Exactly. It depends. Any interesting question. OK. so With all these difficulties, I think I'm required by hipster law to ask this question. You've got, you could have taken the other path where OCaml is compiling to the OCaml byte code. Yeah. OVM. Is it called OVM? I'm just guessing. It's called, uh, oh, the, oh, the. It's not like the JVM, but for O. I don't, I don't know if it's called OVM. I've never heard that before. Okay. I'm making it up. I think it's the.
00:55:50
Speaker
The name of the binary is Camel Run. Camel Run. OK. OK. But I don't know what the VM is called. Wouldn't you have fewer of these like making it readable problems if you stepped in at that point and said instead of generating OCaml byte code, we'll generate Wasm? Oh, interesting. OK,
00:56:15
Speaker
like okay like a new compiler back end for OCaml that generates Wasm. Yeah, yeah. And then you don't have to worry about readability because no one's worrying about it at all. Right. That's, that's, this is, well, first of all, a great question and it's, it's a great point as well. I think there are a few projects on their way. I don't, I'm not very familiar with the ecosystem there or like what the players are, but I believe there are a few, at least two or three competing projects to generate Wasm from OCaml at this point.
00:56:48
Speaker
um I can't tell you their names. I haven't kept kept up. Fair enough. but But I know they exist. the To answer your specific question though,
00:57:02
Speaker
I don't think we're in a world there still where where that is desirable for everyone and their use case. um From the perspective of Well, even if we ignore the technical limitations of like Wasm doesn't have a GC and OCaml is a GC language, I think there's a proposal that's under works or like it has just come out recently or something like that. Oh, yeah. Or otherwise you'd have to start implementing a garbage collector in Wasm first before you could do anything. Correct. Yes. And I think there there are some projects who who went in that direction.
00:57:40
Speaker
ah But but the other the the the other reason which I believe is a bit stronger, at least to me in my use cases, is that people don't really work with Wasm directly from my understanding. a lot of the A lot of the code is still... Or let's put it this way.
00:58:07
Speaker
Wasm generates like this black box for you. It was originally meant to be able to write these high-performance programs like rendering engines and games ah and have them run in the browser with minimal modifications.
00:58:24
Speaker
I'm not too familiar what the FFI, the interrupt story looks like in Wasm. like How do you call JavaScript functions from Wasm and otherwise how do you expose like an interface from Wasm to JavaScript? So this could be you know my ignorance showing here because maybe these problems are all solved and I don't know about them. Or it could be that the story is is not that fully fleshed out.
00:58:51
Speaker
Yeah, I'm not up to speed with it, but my impression is it's a bit more like doing RPC to a nearby separate citizen.

React Integration with ReasonML

00:59:00
Speaker
Which makes sense to me, um right because of the like the sandboxing the requirements. So what you do get with Melange and like all the compile to JS and why people are still doing compile to JS these days is you get access to the like the entire set of libraries that exist on NPM. You can call them and interrupt with them natively with code that is running on the same process, right, in the same thread. This is this is my understanding of the trade-offs. Yeah, OK. I think i think the the market for actual JavaScript output is is still very much there and will be for a long time.
00:59:43
Speaker
I think so too. like I was trying to think how... and Maybe this is something that I should go and look look up after the the podcast, which is, how do you call like how do you write a ReactJS application in Wasm? I'm not sure you do. I've never seen this, and I'm not sure you do either. right and so like For the the specific use case of...
01:00:10
Speaker
say like Ahrefs, who have a specific use case of developing their ReactJS applications in OCaml, using ReactJS, using Reason React. right this is This is very much a ah use case that i I'd like to see how supported in in that scenario. So if we zoom back out in into that,
01:00:34
Speaker
What do I do today if I'm an OCaml developer wanting to write React? Is there like an OCaml library that looks a lot like React? Or are there bindings into actual React? What's it look like?
01:00:47
Speaker
Yeah, this is this is something that we touched a bit upon when I mentioned the the like the boundary, right the the what happens when you want to call one thing from the other. um i mean I think I mentioned at the start of the of the episode how OCaml itself, right when you're compiling to Native, has an interesting Interop story to C, where if you don't have this library available to you in your chemical system, you can go and you can link to some C library, write bindings and call call into that C library. In Melange, we actually use the same mechanism, but instead of C, we're calling out to JavaScript. so the way that The way that works is you define the name of the function that you want to call.
01:01:30
Speaker
It defined what that signature the signature of that function looks like in OCaml terms. This is the unsafe part because you sort of have to guess, and JavaScript is very dynamic. Right, yeah. right So it's on you to get the type signature of the JavaScript function correct. It's on you, for sure. right And then we we added a PPX that interprets a few attributes that generates all the constructs, that allows you to generate all the like syntax constructs that yeah JavaScript has.
01:02:00
Speaker
Or how do you generate like a a new like object call? How do you define something on a prototype? right How do you define a class? um Things like that. And so this is the approach that we took for ReactJS. There is the library called Reason React. This is a library that precedes Melange even, right? It was written. um and like When Reason ML, the project started and was still using BuckleScript, we took it and ran away with it

Personal Development of Melange

01:02:30
Speaker
as well. um So we we use
01:02:33
Speaker
Reason React, it has a very nice ah PPX, again, a preprocessor extension that interprets the Reason ML JSX, which is built into the language. And and generates React ah like JSX or create element calls. So what? i can I'm writing OCaml and I can include HTML tags through JSX.
01:03:03
Speaker
This is, if you're if you write ReasonML, yes. ReasonML has had JSX support. but yeah like you know This alternative syntax for OCaml, but it has right? and It was developed at Facebook with the goal of writing ReactJS programs in mind sort of from day one. So JSX was included and that's like a big selling point, right? yeah So I am writing OCaml, but it looks an awful lot like JavaScript and JSX, and it's outputting to JavaScript. Yes, that's right. That's right. The thing there is, the JSX in ReasonML is very much reusable from the perspective that, I mean, generalizable, right? From the perspective that if you wanted, you could write, say,
01:04:00
Speaker
People in the general case use JSX to output ReactJS elements to the browser, right?
01:04:11
Speaker
That doesn't mean that it's the only use case for ReasonML's JSX. You could, for example, imagine a a your own pretty printer definition that uses JSX for for for tagging, but like pretty printing directives.
01:04:26
Speaker
any sort of internal like DSL domain specific language that you can write with JSX. You can, you can write it in ReasonML as long as you also write the like sort of the runtime and the transformations. Okay. So it's like, yeah it's, it's generalizable in that sense. This is, I mean, you could almost wonder where the OCaml is. It's very much under the surface in this stack, right?
01:04:56
Speaker
It is, I'd say, yeah, it is very much under the surface at just the AST level. problem And what you're getting for that is a combination of the compiler, which is an advanced compiler and the whole backend ecosystem. When you actually start wanting to use reasons server side world. Yeah, exactly. I'd say.
01:05:24
Speaker
For the backend, if you're if you're writing it in the backend, OCaml is very much everywhere and in the and the scenario that we're painting. Otherwise, for for the melange part of the again the scenario,
01:05:45
Speaker
I would maybe say that OCaml is mostly just in the tooling. right And then the surface looks a whole lot like JavaScript. And what you do get and what you run is definitely JavaScript. OK. So it seems like you are still blurring those lines between OCaml developers that want the browser and JavaScript developers that want OCaml. I think that's a fair assumption. I think I am blurring those lines because I identify with both.
01:06:19
Speaker
And sometimes I need one of the use cases where I'm coming from one direction, and sometimes I need the other one where I'm coming from the other direction. Yeah, I can totally say that. That's a good thing in my book. So why don't we again step back a bit and say, where do you come in as a user of this? Because you're doing all this work, but what does it do for you when you're not working on it? How have you put it to work?
01:06:45
Speaker
Yeah, um I have a few ah few apps here and there. This is actually a a very funny story because um I think I found myself writing Melange and writing all the tooling around it because I wanted to use it. um I wanted something to exist to write my own applications because this would be my preferred way of writing JavaScript and shipping um code on the browser, for example.
01:07:14
Speaker
um what What happened in and in practicality was that I found myself writing mostly the compiler and the tooling around it and really never having time to go and then write my own applications. Yeah. That's familiar. That's familiar. So ah like I have written some things here and there. I have some some private some like
01:07:46
Speaker
private applications that i that are you know not out there. I have some things that I'm working on that that are in Malange. I write Malange applications all the time to to like either in the form of compiler tests or otherwise to you know test out new compiler tooling. um But I'd i'd say um there' there I don't think there's anything public out there other than maybe the the Melange Playground, which um ah yeah it's melange.re slash.playground, I believe, which is an um like ah an online program playground where you can see how you can write OCaml on like the left-hand pane and ah see the JavaScript that it generates on the right-hand side.
01:08:33
Speaker
Ah, and who's that? Sending the source code to a server and compiling it. It's all happening in the browser. It is all happening in the browser. and So this is sort of where the but well everywhere i I could maybe yeah consider ah the Dr. Frankenstein, right, but having created the monster, um where what we actually do is We compile, unfortunately, Melange is still not self-hosted. self-posted um So what we do do is we compile Melange to JavaScript using JS of OCaml, which is the other player in the the OCaml ecosystem. And then we have this this big bundle of code that is the Melange compiler.
01:09:26
Speaker
and then that we just treat as sort of a black box. It has an interface that allows you to feed in OCaml or ReasonML and get out some JavaScript compiled by Melange. And then we put a like a Melange web application around it. Right. So it's it's it's an organ. Right. OK. And you're going to have to remind me now you've brought it up. So why?
01:09:57
Speaker
You're using JS of OCaml to compile that comp... That... This is a hard enough question to phrase because it's so meta.
01:10:10
Speaker
You're using JSFO-CAML to compile the melange compiler to JavaScript. This is correct. why what the js of o What's the drawback of the JSFO-CAML compiler that makes you still want to write melange? For sure. the yeah Again, I think this is ah this a great question. and sort of One of the but reasons why melange exists at all is is why is JSFO-CAML not sufficient for our use cases?
01:10:41
Speaker
um There are a few reasons. ah One of them is I mentioned before how Malange hooks into the like the lambda layer, right the lambda intermediate representation, whereas JS of OCaml takes the OCaml bytecode and interprets that at compile time to generate JavaScript. um There are a few trade-offs that have to be made when you don't have all the information that that you have at the lambda representation that has been lost between that and the bytecode. Yeah. Information gets thrown away to get there. and Exactly. yeah man So we we talked a lot about how like we represent OCaml structures in
01:11:24
Speaker
In JavaScript, when compiling through melange, how that affects readability of the generated code and like the the different structures that you you can like you you can then work with um to generate um JavaScript.
01:11:40
Speaker
so One of those is, for example, how... I'll go with the records example again, where naming information for the keys search is just not preserved.
01:11:53
Speaker
between one and the other, right yeah for example. So the the you you can't represent those as JavaScript objects, for example, if you're if you're going through JS of OCaml. There's there's like all these particularities about um mostly how like mostly around representation of OCaml constructs in JavaScript, and then how that also affects performance. If you don't have all the information available, you you need to to ah add a lot more indirection and add a lot more runtime ah if you're going with the latter case.
01:12:32
Speaker
right The big advantage though, right like because I only i only i only mentioned trade-offs, but JS Oval Campbell has a lot of advantages over Melange as well. right Because in engineering, everything is always about trade-offs. It depends. Exactly. like One solution that is strictly better than the other, or and that those are those cases are very few.
01:12:56
Speaker
um So the the big advantage is that JS of OCaml offers is the ability to support most, if not all, the OCaml language. right I mentioned before how it's like there's a ah some modules, some standard library ah write modules, and some other libraries, some constructs that we can support in the launch. I talked about effect handlers, for example. right And that is something that JS of OCaml does
01:13:27
Speaker
um support. um I think the the route, for example, that they took is they added the the the continuation argument to the end of every function if you're compiling effect handlers. But this means that every function in your yourre your program needs to have this last argument. And then if you want to call that from JavaScript, you need to provide an adapter so that you know how to call that. right So again, like you're incur you're incurring runtime and like the
01:13:55
Speaker
the representation doesn't isn't isn't as trivially trivially and understood or documentable even. um But then the big advantage is that you support a whole lot more.
01:14:07
Speaker
Right. Yeah.

Getting Started with Melange

01:14:09
Speaker
So what we in a way, you could separate it out as you're compiling, in Melange, you're compiling still a fairly high level language to another high level language. Whereas in JSFO Camel, you are basically bytecode to different bytecode. I think that's a great way of putting it. Absolutely. Yeah. Yeah. Okay. I can see the trade-offs. So let's Let's zoom out then to the practicalities of someone else using this, if they've decided. because um Certainly, I'll put my cards on the table and say, I don't want to write JavaScript. I'm happy to say that. I may want to write TypeScript, and I have very different feelings about TypeScript than JavaScript, but you know I like writing PureScript. If I wanted to say, okay, let's go reason ML, try this out.
01:15:00
Speaker
and see how it feels to me, what's the best way to get started? I'd say the best way to get started is going to melange.re. It's a website where we've put um our getting started instructions. We put all the documentation. um There's a very big section on like how to... Because I'll make these the the society, I'd say, like you don't want to ja you don't want to write JavaScript, but I think you'll still find yourself um
01:15:32
Speaker
working with a lot of JavaScript if you're shipping to a JavaScript platform. So you'll have to do interop with JavaScript on every platform, even if just the platform APIs, right? um yeah At some point, you'll need to call them. So we have ah you have a long a long section of where we document um how to do all of that, how to how to write your um you know the like the code at the boundary, how to consume libraries, how to to orchestrate the builds. um You can also join the OCaml Discord or the Reason ML Discord. We're always there. We try to be online as much as possible, help you out. That's, I think, the best way to get started. Cool. And um i mean this is a really hard question to give a specific answer, but give me your your subjective opinion. How mature is this stack?
01:16:22
Speaker
the Yeah, this this is a hard question. I think, give you a bit like ah of of history maybe. I think maybe two, three years ago, we started from a point where effectively what we had was pieces like this this joint, this jointed set of tooling, right? Just pieces that existed. You could sort of put them together, but you'd have to do everything manually yourself.
01:16:52
Speaker
um A big part of our our work from two, three years ago until now has been, how do we put all of these things together behind the scenes so that you mostly don't have to worry about that yourself? um And so we added support for Melange in the OCaml build system, made it work seamlessly with the OCaml platform, ah and have been really fixing a lot of code along the way.
01:17:22
Speaker
um We're at a point where we've shipped four major versions of Melange. And we have, I'd say, a lot of users using Melange in production these days. ah The biggest one being azurefs.com, as as I mentioned. help So I'd say it is stable right from the perspective of you can ship it it to production.
01:17:53
Speaker
and
01:17:56
Speaker
not expect any like major surprises in in surprises coming from like your like choice of tooling in this case. right yeah Which is where you want to be like on anything that you depend as critical infrastructure effectively. um However,
01:18:20
Speaker
I'd say the ecosystem is still very young. You'll find that if you ship this, if you ship Melange, I'd say we're still maybe in the early adopter phase where the ecosystem is not totally there. You'll find that you'll have to write a lot of bindings to JavaScript libraries that exist on NPM, you'll have to maybe write one of two libraries yourself to to to do all

Future of Melange and Episode Wrap-Up

01:18:47
Speaker
you want. You'll have to figure out how how are you're going to configure your build and like where're like where Dune and NoCaml and where a bundler takes over, for example. And those are all choices that you'll have to make yourself and we don't have like any
01:19:05
Speaker
recommendation for, right? So there's a lot, a lot of figuring out, there's a lot of fiddling, but overall like the core, let's put it like this. Like I think if you're experienced with OCaml, you'll be familiar with the melange tooling. If you're new to OCaml, there's a lot to learn.
01:19:31
Speaker
Okay, okay. That's fair. That's kind of what you'd expect, right? Yeah. So that, I mean, that raises perhaps the final question, because I'm assuming you're not now going to focus on writing native ah React and ML date pickers. you're not goingnna You're not going to run off and flesh out that ecosystem. What is your future for this project? What are you working on in the next six months, year?
01:19:59
Speaker
Absolutely. So there are a few things that we want to we want to achieve. um what one One that is always top of mind is developer experience. So we we have ah a front end team right inside Ahrefs that is working with Melange and ReasonML every day.
01:20:23
Speaker
They feel pain points. right And those pain points are reported back to me upstream. and and And this is something that is always something that we need to to keep in mind. So we need to not only fix bugs and like the usability of ReasonML, the language itself.
01:20:43
Speaker
We need to fix bugs that arise with using melange, not only like co-generation bugs, which these days are a few and far between, but mostly around If your compiler gives you an error message and you don't know what to do with it, like whose fault is it, right? Usually it's the compiler because the message is not helpful. So there's a lot of work in developer experience that we're focusing on. um We're also trying to really ship this project that makes it easy to share code between the front end and the back end, right? Between code compiled with Melange
01:21:22
Speaker
versus it or in addition to code compiled to native like how do you Define these like language specific constructs that you alluded to earlier of like ah like sort of like Closure calls them reader conditionals. I kind of like that that that phrasing quite a bit um But basically, you know these compiler directives that conditionalize the back end that you're compiling to ah And then And then the rest of of the work that we need to do is how do we support increasingly more JavaScript constructs and ah the in in the Malange side. The one that I'm thinking of specifically is like dynamic imports. You know how in JavaScript you you have
01:22:10
Speaker
I'll simplify it like two types of imports, one that is synchronous. This is the one that you put at the top level of your file as a declaration. i um I want to import these values from another module. But you also have these dynamic or async imports where you can choose to import some other module or another bundle at runtime. And that is you bundlers usually like hook on that construct to sort of define where they do bundle splitting. So like, Oh, I'll ship like a chunk that is the main application chunk. And then if this imports something else dynamically at runtime, like I'll put that in like a ah ah lot of different logical chunk that doesn't have to be part of the main bundle when you load a webpage. So this is something that for example, is very much on, on the, the melange roadmap. And it's something that we're working on and we're trying to provide a solution that
01:23:07
Speaker
is idiomatic in OCamble while still giving you the benefits of bundle splitting in JavaScript. Okay, yeah. that that It's interesting, that particular point gives a real sense of where you are on the maturity curve. Right. Because that's the kind of thing you only start to worry about once the compiler is actually stable and you people are building stuff and shipping large enough projects. That's a fair point. and And you can do it these days, right? The work, the work that we're trying to do is how to make it idiomatic because melange has effectively an escape hatch where you can write JavaScript code within your ML file, right? And using that, or even using the, the FFI language, the, the the interop language, you can, you can make dynamic import work. And I know,
01:23:57
Speaker
of people who have code bases that are making it work with Melange. It's just that you lose a lot of safety. We talked a little bit about OCaml modules and how like they're very they're very well typed. um You can define signatures for them. So to give you like a little bit of i guess a preview of what's coming and what we're working on is the ability to define a signature or infer a signature that you import dynamically.
01:24:28
Speaker
So that when you you when you do import your OCaml module dynamically, everything is still type safe. And it's as if you were just referring to another module that exists within your o OCaml code base. That's really like the the interesting part of the work is like,
01:24:47
Speaker
how do we do How do we generate a dynamic import for something that we don't include in the bundle? But how is like it preserves the type checking, it preserves the signatures, and you're not like programming in an unsafe way. yeah Yeah, because you don't want to lose the guarantees in the language, and you definitely don't want to make this something that becomes hard in developer space. Absolutely. Yeah. Well, that sounds like a very fun piece of work to um to be working on.
01:25:14
Speaker
It is. Yeah, it is. it It is very fun. It is. There's a lot of research. There's a lot of prototyping, but I think, I think we have some parts figured out. I best leave you to go and carry on with it. That sounds good. Thanks for you very much taking me through it. Thank you so much for having me on. This was great. Cool. Cheers.
01:25:35
Speaker
Thank you, Antonio. So the first thing I should say before we go is if you want to support Antonio's work, you can sponsor him on GitHub. There's a link to that page in the show notes below. Also, consider getting your company to sponsor him instead, because a large amount to an independent open source developer is a rounding error to the average company's IT budget. So if you can persuade the right person, do that. It'll be great for everyone.
01:26:02
Speaker
While we're on that topic, I should probably say there is a link to the Developer Voices Patreon account if you would also like to sponsor future episodes of this podcast and keep the show running. And of course, the show notes the right place to look for those links and any links to the projects we discussed during this episode. So go look there for all your link goodness.
01:26:22
Speaker
We'll be back next week with another brilliant mind from the world of software development. So make sure you're subscribed. And if you enjoyed this discussion, please give it a like and maybe share it with a friend.
01:26:33
Speaker
Anything else? Yes, if you have any suggestions for future guests, you can find my contact details. Please get in touch. I'm working through the backlog, but I always like more suggestions, so I'd love to hear from you. Thank you. And with that, it just remains for me to say, I've been your host, Chris Jenkins. This has been Developer Voices with Antonio Monteiro. Thanks for listening.