Hosted by Charles Lowell on July 9th, 2020.

In this episode, Marcell Cutts and Shane Wilson explain ReasonML and repkgs to Charles: What are they? What are they for? How do you use them?

00:38 - Reason

03:25 - BuckleScript

06:01 - Reason + BuckleScript

16:07 - Reason: Interoperation & Adoption

30:00 - Operating at the Compiler Level vs the Run-Time Level

  • ppx (pre-processor extension)

34:29 - Last thoughts on, and why use Reason?

44:43 - repkgs

Transcript:

CHARLES: Hello and welcome to The Frontside podcast, a place where we talk about user interfaces and everything that you need to know to build them right. My name is Charles Lowell, a software developer at Frontside. And today, here to talk with me about many interesting topics. One of them being ReasonML, we have Shane Wilson, the Founder of Peyk Inc, and Marcel Cutts, Founder of Asgard Enterprises. Welcome, gentlemen.

MARCEL: Hello. Hello.

SHANE: Thanks for having us.

CHARLES: Yeah. So, I guess we should start out just talking about why ReasonML. I understand that both of you guys have some experience with it. New languages are all the rage. So, what drew you to it and have you found it?

MARCEL: That's a great question. I'm afraid my history is going to be spotted and will really demonstrate how much pubs are an integral part of the UK tech scene. I got into ReasonML maybe four years ago at this point when I found it on some hacker news post. And I asked on Twitter, "Hey, is anyone running a ReasonML meetup in London?" And I also, maybe around point one. And then by point for a point five, someone said, "Oh, no, wait. I think there is one." "Oh, does that mean you're starting one?" And then by point six, I thought this was a good idea. So, I began to run the ReasonML London Meetup, which end up being one of the bigger ones in the world. And along the way, it [inaudible] to learn some ReasonML and why it exists, which ended up being quite fascinating. And I did quite a few talks around it around the world. And it has stuck with me since. It's a very fascinating intersection of many kinds of approaches to programming as well as technological applications with a lot of history as well stemming from its origins, OCaml. So, it's a bit of a unique beast and it has kept me interested since.

SHANE: I came about it because I've been doing JavaScript for quite a long time. But I've always liked compile to JavaScript languages. Maybe six years ago or longer, I started looking into Clojure and I got pretty heavy into Clojure and on ClojureScript. And I was always looking for a reason to write ClojureScript as a compiler to JavaScript language, but it never took off. Do I kind of hope that it did? A lot of people use it, but it never really took off. And then when I was recently looking into how do I write JavaScript Node applications but without having to write JavaScript or setting up all the toolchains, I came across ReasonML along with BuckleScript. And I was really pushing how you could write a language with a lot more features and JavaScript comes built in with but compiles down to JavaScript that's very readable. That was a big selling point. So, when I started looking into it, that your output was basically JavaScript. It wasn't like a computer had written it. It looks often like a person had written the JavaScript. I thought that was very impressive. And it made it a lot easier for me to think that I could sneak it in to a project somewhere. Or I could just make my own little ReasonML toolchain, output a file, and then just not tell anybody and no one would even know.

MARCEL: Some say that I have in fact made several branches for many client projects which secretly have been produced from BuckleScript output and then slightly tied it and no one's ever found out.

CHARLES: So now, what is BuckleScript for the uninitiated?

MARCEL: We can go from the top down. ReasonML is a meta language as well as a toolchain and some documentation utilities for a language called OCaml. OCaml is a 20 plus-year old [inaudible] systems language, the kind of language you expect someone of a long gray beard to be writing.

CHARLES: It's one of the spiritual ancestors of Haskell, isn't it? Or no?

MARCEL: That's a great question. I'm sure what the familial tree between those two would be. I think it's an ML language, which means that a lot of that will bleed into the Haskell way of thinking.

CHARLES: Okay.

MARCEL: About a few years ago, I think about four or five years ago, the chap who invented React left the spotlight and retreated into the shadows and left other people to be the spokesperson for that framework. Remember everyone that Jordan Walke is the person who made React, not Dan Abramov, even though he is the star of the show for many things React-related. In his spare time, what he did is work on this thing called ReasonML, which is a new syntax and toolchain for OCaml, which makes writing OCaml look a lot like writing JavaScript. And this was a way of trying to get people to write in a more functional and type safe way.

At this point, you may be saying, "Great, you can write OCaml like JavaScript, but it's still OCaml." The missing piece is something called BuckleScript, which was developed by an expensive keyboard company called Bloomberg. And they had this layout because OCaml itself is a very pluggable and modular compilation system. They plugged a single BuckleScript [inaudible] compiling to bytecode or [inaudible] or you could compile directly to JavaScript. This runs a lot of the internals of Bloomberg that have a surprisingly large amount of JavaScript and Node in there, and they wanted to be 100% sure about what they're getting because with OCaml, you do get and ReasonML by extension, you get 100% type safety all the time. Unless you have big exception flags, unlike something like TypesSript, for example, where you sort of [inaudible] but you don't quite have the same certainty. And also, you don't have a lot of these syntactical avenues that a language base and types will give you, things like variance or being able to switch on type definitions.

CHARLES: If I'm understanding then correctly, ReasonML, the syntax actually is 100%, it is OCaml. It compiles down to BuckleScript. Reason is this toolchain for OCaml that outputs this dialect of JavaScript called BuckleScript?

MARCEL: Yeah. The combination of BuckleScript and reason together give you the syntax and the output. Have there been discussions about trying to make this clearer and saying what each component actually does? Yes. Have they been very [inaudible]? Also, yes. [Inaudible] reason to syntax and then BuckleScript compilation that leads to the readable JavaScript that Shane mentioned earlier. And this has had some interesting pickup and it was quite a contender in the original for People 4 Projects battling for the type space early on, which was Flow, TypeScript, Elm, and ReasonML.

TypeScipt has been around for nine years at this point. I think it came out in 2011. It's been around for much longer than people remember because it just took a long time, a lot of [inaudible] backing to get to the front spot. And it is continuing to slowly develop to this day. It hasn't quite got the same acceleration it did at the beginning, as Shane mentioned. But it still has a ton of interesting applications and it is used in the law of production applications throughout the world. For example, all of Facebook Messenger is written in ReasonML for performance and certainty reasons.

CHARLES: Oh, okay. Interesting. I started out using type systems like Java and C++ and C, and I very much considered myself kind of a refugee from these brutal typing regimes. I fled to the land of JavaScript and of Ruby, and even places like Perl and Python kind of to escape types. I've been slowly getting back into it with things like TypeScript. So, what are the surprising aspects of the type safety that are really, really done well? Because I can definitely say having gotten a taste of TypeScript in the last few years, I can see there are ways to do a TypeScript or a typing system that really feel lightweight and feel like they're helping you and feel like a tailwind rather than a slog. And so, what are those experiences in Reason that really stand out?

SHANE: For me, I've never used in ML language seriously before other than like some toy projects. So, for me, most of my experience with types has either been Java or TypeScript. And ReasonML, I'd much prefer that type system. I'm not going to get too technical because quite frankly, I don't really know the technical things to say here. But when I work even with TypeScript, I feel like I'm adding types because TypeScript wants me to and needs them. Whereas in ReasonML, first of all, you don't have to add a lot of types. You almost never have to actually type the code that you're writing, maybe type modules or create types. But the actual code that you're writing with all the flow and the logic is almost never a type in there. ReasonML and the OCaml figured that out for you, which I think is amazing and it doesn't get in my way anymore. And when I write ReasonML types, I feel like I'm doing that to help me, not to help the language. I want to better define the problem that I'm solving and help create barriers for how to solve that, put data in a place that it should be, help with my logic flow, and I want to make those changes and the language is helping me make those changes. Whereas most of my time and experience with types, I know what I want to do and the types aren't happy, and so I have to change my work to manage the types.

CHARLES: Right. You're having to kind of spoon feed the compiler and throw spaghetti at the wall and see which come kind of weird combination of types and generics fit the problem and make the compiler happy.

MARCEL: Yeah. Java really has done an absolutely excellent job at ruining types for everyone for quite a while. The worst PR campaign you can imagine. But it's important to know that there are more than one kind of type system. There are two big schools. One being nominal typing which is the kind of Java C# thing that has burned into people's memories and gives them sleepless nightmares, where you try to compare the names of things and the way the things I described and to figure out if they have equivalent to that sort of thing. But the thing that things like Haskell, Elm, and ReasonML, OCaml too, is called structural typing where it's based entirely on the structure of your data, which means you can do much more interesting things and it can get out of the way a lot more. And it has something called the Hindley-Milner type system, I want to say, to try and infer the types to the best of its ability with as much certainty as possible from your code. And it is mathematically provable that the Hindley-Milner type system is the best type inference engine that currently exists. So, you do end up typing precious little when you're actually writing ReasonML. But you still have complete type certainty, which is very helpful, especially if you compare doing this to something like TypeScript, where I think it's not unreasonable to say that folks like to type all the things that are easy to type, for example, dysfunction [inaudible] string. But often it is much more difficult to type things like the response from an API that could be in all kinds of structures or the state of the application, which could be in X many permutations, which is much more difficult to describe with the typing tools that you get in that language set.

CHARLES: Is there any particular example of something recently where we can compare, say, an implementation in TypeScript to something in Reason? I just want to make sure that we have like some way to focus. Because I believe you, but it's just -- and I definitely have this experience where I feel like I'm trying to satisfy TypeScript and the errors are cryptic and, yeah. And so, I'm trying to get a glimpse into what's a particular use case that I would find frustrating with TypeScript that Reason would swoop in and solve all the things.

SHANE: I don't know if I can think off-hand of something that obvious, although there might be. But I know one big feature that ReasonML has is like the switches. You can switch on a type and I guess you can have dynamic typing. So, instead of having to create a whole interface, you can just say -- basically it's it's like here's a string, but it's not a string. It's like I just have a label and it's now a type. And you can do type checking on these dynamic types. So, I've used that recently to manage errors in a product I was running where any random error I want to come up with, I could give it a label. Oh, and so types can also get past data. So, my dynamic error label like file read error can actually take in values like a file pointer, like a link to a file. And then when I'm accessing that error later, I can pull out all this data. So, you don't have to create these complicated structures and try and pass them around. You can just create a type and then it will have all the data in with it. And then you can do a switch check on that type and destructure all the things that you need.

It's kind of hard to explain, especially when I don't know the details of what I'm saying. But the best I can say is it's just the feeling you get when you're programing, you don't get the frustration. When I work with the types, I'm always glad that the types have helped me. I'm very rarely frustrated that the types are getting in my way.

CHARLES: It sounds like the types are just so deeply integrated into the way that everything is done. It's not so much annotating stuff to make sure that the ends of your apparati line up with each other so much as deeply integrated with how you actually express the flow of the program. Is that a fair way to say it?

MARCEL: Yeah.

SHANE: Yeah, it sounds good.

MARCEL: I think I can think of a decent example that demonstrates a difference that types can make. In TypeScript and JavaScript, its [inaudible], of course. You often end up with these situations that folks call being stringly typed. So, a component, if you're doing a React, can take a number of props and maybe the component has different states, have a button that can be a default one or a call to action button or a more subdued button, if it's an option that you don't want to be invisible. So, there are many ways of trying to get it done. But one thing that often happens is you parse on a string of the correct name that you wanted this thing to do. And then maybe inside a component, you have a switch and then you have all the different kinds of strings that you could expect together. But you could get any kind of string, really. Nothing prevents you. So, with the switch and variance system that Shane was mentioning, you automatically get [inaudible] pattern matching. So, you can say these are these three modes and here these types of that mode. If you then start to do a pattern match, which is, you know, think of it as a switch, but 11,000 times stronger, it will tell you, "Hey, no. You forgot one because there's this other state that you didn't mention." And also, what you're going to do if you don't hit any of this, but you can't because, of course, the compiler will catch it before you get there. This means you don't end up getting into strange situations because you're parsing strings on the application and you're hoping that you remembered all the [inaudible] and account of every case.

And in addition to this, one thing that you find very pleasing on Reason, it brings you joy to writing this. It's a very, very, very fast feedback loop. We're going to talk all about TypeScript because that's kind of a merge as the frontrunner of adding vague types to the JavaScript universe. But TypeScript doesn't check the whole application every time you make a change. BuckleScript does and it can do these compiles in subsecond for very, very, very large projects, which means that you always have confidence in your application as a whole as you continue to type and you don't have to like wait or go back or figure out how something doesn't make sense somewhere else. And this really short feedback loop combined with the fact you don't really need to have all these things, like I said, [inaudible] type system, ESLint, or Prettier that hold your hand means that you have a very satisfying and streamlined experience as you go along compared to the, I think, expected amount of waiting you might do in a regular TypeScript project.

CHARLES: Yeah, that begs an interesting question because TypeScript does seem to evolved as the front runner of a typed JavaScript development system. And I think that's owing in no small part to the fact that it's very easy to adopt incrementally. You can just switch TypeScript. You can just rename all your JavaScript files to TypeScript and you're off to the races. And you have kind of a pass through compilation. There are compilers out there like the Babel compiler that just strip the type annotations and you're good to go, and then you can very easily ramp up your usage of the types. So, I would say, for example, in my own experience with TypeScript, we started out with very loose adherence to the norms of the TypeScript community. And then now most of the code that we write uses the strictest possible settings because those tend to be the most helpful in terms of development, catching errors earlier, things like that. But it's definitely, if you start that way, it is kind of against the norms of normal JavaScript. And so, there is this very clear evolution or very easy way to adopt. So, I guess my question is for Reason, what's the story for inter operation and what's the story for adoption? So, I've got an existing JavaScript code base, how do I sneakily introduce Reason?

SHANE: One way you can do it is because, as Marcel was saying, the compilation is so fast, you can just add it as another step. So, you can set up your BuckleScript compiler and write some ReasonML code and have it compile down into JavaScript or even TypeScript, because there's a plugin called gentype, which will just generate types for you and you can then pass through TypeScript types so you can get perfect TypeScript types if you're using a library. And by the time you finish writing the ReasonML code, it compiles very fast and then you can just have whatever TypeScript watcher watching all the TypeScript files and it will see, "Oh, that TypeScript file is changed," and it will recompile and then you'll get whatever your program is.

So, it's kind of easy to add it as a sidestep. I think the BuckleScript people have said they don't really try and integrate it into the other tools as like a first class because they want control over so much, because they do so much. And by having all that control, they can build it that quickly. But if you wanted to, you could just add a little folder and then put all your ML code there and just have it compile. And then your other watchers just see the compiled files and it works.

That's actually what I've done where I wanted my interface to be TypeScript, but I wanted my actual code to be ReasonML. And so, I have one TypeScript file, which is like the index entry point of the program. And then that TypeScript file reads my generated TypeScript files that don't really exist before I run anything. And then I would just have the BuckleScript compiler watching, it builds on my TypeScript files and then I will run like Yarn or whatever, and that goes into my TypeScript entry point, which then finds all those that build TypeScript files and it just runs. It doesn't even know the difference. So, it's not the worst setup, if you want it to.

CHARLES: So, then you're calling your Reason code from JavaScript. What about the other way around, like if you want to use existing NPM packages inside Reason, especially ones that really haven't been developed for Reason development at all? I mean, this kind of a pain point with TypeScript, even though there's the definitely typed repository where you get 98% of the typings correct, but still, there's a lot of quirks and [inaudible] and stuff doesn't line up. Fundamentally, there's JavaScript APIs that don't really work with a strongly type system. They're hard to type. What's the story, I guess, for using existing JavaScript code?

MARCEL: You do have to write some level of interop to give it some types. But the nice thing is that there are, as you mentioned, some things are just difficult to type because a few of the more dynamic things that JavaScript can do is difficult to express in TypeScript. But the type system for Reason is a little more mature with full features on it. It lets you do both imperative and functional styles of code, lets you do mutations if you want to do performance. So, you could do a much better job of describing what's happening on the other side.

CHARLES: Okay.

MARCEL: There are also a few tools to help you take existing TypeScript definitions and work backwards. But if you're just picking up a random JavaScript library off the Internet that hasn't no way been typed, you would have the same pains as you would for TypeScript. But much like TypeScript, there are already libraries. I think it's called Redex is the website one goes to when they want to see which of their packages already have ReasonML definitions.

CHARLES: What would you do? So, one of the things before we even started using TypeScript, a lot of our libraries were written in JavaScript and we had a lot of requests for, "Hey, let's make the typings." And I always found putting stuff on, definitely typed wasn't optimal because if you released a new version of a library that had breaking API changes, the types were decoupled from that. And so really, the interface definitions being decoupled from the actual source code was a problem. So, even before we started doing stuff in TypeScript, we started shipping declaration files with the actual code. So, taking time to make the TypeScript declarations with the JavaScript code, even though the projects were written in JavaScript, it just made it more adoptable by people who were using TypeScript. So, is there an equivalent in Reason? Can I just say, "I've got this thing that I've got in JavaScript or TypeScript or whatever, but I'm going to write a reason API for it." Can you ship that type of adapter with your library and make it available in package JSON, so that anybody using Reason can just, with no fuss, no muss, use your code?

SHANE: In that case, a lot of times, you just publish at npm and there's somewhat of a standard where you prefix your package either with bs-, like BuckleScript. I think they're trying to move that to re for Reason just to try and reduce the confusion of what is BuckleScript, what is Reason. But the way you do that is you ship your ReasonML code, and then you add that package to your BuckleScript dependency list. And so, BuckleScript can now go into that package, compile the ReasonML code, and then you can use like the ReasonML types in your package. So, that's how you would pass on those types. If you and type a JavaScript language and you want someone else to reuse your types, you can just publish it as re- package name. And then you can use that in a ReasonML project.

MARCEL: One thing to also remember is that we are very used to having a ton of dependencies inside the JavaScript universe, which is why the idea of having to write bindings for a lot of packages seems incredibly daunting. But what's important to remember is that ReasonML is a much more full-featured language and has a bunch of libraries and stuff pre-built. So often, when we want to do something with functional and we would take a Lodash as a library and then think, "Wow, it's always easy to type together." The outcome of having a mature language that you're basing this meta language on means that you have a lot of these things you'd normally get dependencies for is completely built-in already. And you end up having a lot fewer dependencies that you need to worry about.

CHARLES: Okay. Meaning, for example?

SHANE: I guess you wouldn't need things like Lodash as much.

CHARLES: Okay. So just all your things like transforming data structures and stuff like that?

SHANE: Yeah, a lot of the data structure manipulation functions are already built in.

CHARLES: But it's still all the stuff like file systems and network you have to receive from the environment. For example, I assume you can run Reason in both node and the browser, right?

MARCEL: Yeah. If you compile to JavaScript, it can run wherever you want.

CHARLES: Okay.

MARCEL: It can also compile to Native, if you really want it to run in the machine.

CHARLES: Shane, you mentioned ClojureScript and I actually was very interested in Clojure and ClojureScript at one point. And one of the biggest problems for me with ClojureScript was it depended on the Clojure toolchain. So, in order to compile a ClojureScript, I actually needed to have Java installed. I needed to have the Maven package manager to pull down dependencies and assemble these things. And that was kind of one that introduced a bit of a papercut into getting the environment set up, because, hey, I'm a JavaScript developer. Why do I have to go install a functioning Clojure environment? And then the second thing was it meant that actually using the compilation tools was not available in a pure JavaScript environment. I think one of the kind of powerful things we've seen is these systems that are written in JavaScript, for example, TypeScript is itself written in JavaScript. And so, it means that you can run TypeScript compilation inside of a browser with nothing more than what's available in the browser. So, what does the toolchain look like for ReasonML? Is it in JavaScript?

SHANE: Yeah. Well, just to back up. ClojureScript actually is all JavaScript now.

CHARLES: Oh, it is.

SHANE: Yeah. You don't need Java anymore.

CHARLES: Okay. That's good.

SHANE: You can install it from npm. And there's a new -- I'm not super up to date on this, but there's I think a new library, shadow, I think it's called. It basically lets you compile down your ClojureScript into different styles of JavaScript, like [inaudible] module or a package. So, they made a lot of progress on that space. It does still depend on a lot of the ClojureScript libraries, so the outputed file for like an application is probably fine. But if you wanted to make in a JavaScript style many little libraries, each of those libraries has to have this really heavy dependency in it. So, it's not ideal for that. But you don't need Java anymore. Big improvement on that end. But on the BuckleScript side, you can install with npm. So, you just npm add your BuckleScript compiler and then you just run it as just any other node executable.

CHARLES: Okay. Well, that's handy. So, there's a totally separate Reason compiler. But is this syntax exactly equivalent to OCaml? I'm still a little bit confused on that point. Or is it just a dialect?

MARCEL: Reason is part of the toolchain and also one of the different ways of writing OCaml. It gives you a very JavaScript like syntax. And essentially imagine a bunch of pluggable compilers that sit at the bottom of the toolchain, and one of those is BuckleScript. So, you write your ReasonML that looks like JavaScript. And then it gets further down to this BuckleScript layer and the BuckleScript layer turned it into JavaScript or TypeScript, whatever you prefer.

CHARLES: I see. Okay. So, BuckleScript is and of its own a unique language.

MARCEL: Yeah. One could program in it but very few people do. It's a very powerful middle module.

CHARLES: Okay.

SHANE: This conversation is made a little more confusing by the fact that BuckleScript just released a new version of their syntax, which is very JavaScript centric. So even though it's technically like Reason, it's even more JavaScript focused than the Reason you might write if you were doing Reason Native. So instead of defaulting to lists, it defaults to JavaScript arrays. The object notation is now just defaulting to JavaScript objects. There's been a kind of another split that just happened where now you have ReasonML syntax that would work on Reason Native. And it has a new ReasonML syntax with more BuckleScript embedded into it, which would work with the BuckleScript compiler. So, there's even more splitting happening, which is probably going to confuse more people. But I think overall, it's for a good cause because the syntax is much more simple, especially if you're coming from JavaScript. There's a lot of weird things that happened which don't happen anymore.

MARCEL: It is true. There were initially quite a lot of good momentum on this and a good uptake. And the growth of ReasonML, while it's still perfectly usable, very reasonable choice for all your projects. One of the reasons I feel it hasn't done as well is because of these continuing small confusions and decisions and perhaps a lack of more central leadership. Ostensibly, it's run by Facebook, but that's not really the case, in pragmatic terms, which means that it can be harder to get people started. And perhaps one of the reasons why something more focused like TypeScript, which is very clear, singular documentation site is doing better out there in the wide world of the software [inaudible].

CHARLES: But you do think that it is possible to adopt incrementally too, should you want to? Even though it's distributed in terms of documentation and authority and maybe who's writing the roadmap?

MARCEL: Yeah, absolutely. The interop story is very well thought out. And especially with this new update that Shane mentioned, it gets even easier to write code that turns into that kind of JavaScript that you expect. But with all the benefits of higher percent type safety speed, much smaller tooling surface and all the other benefits.

CHARLES: Right. I wanted to ask another question about the types system. One of the things that I actually find frustrating about TypeScript and that I also loved about ClojureScript, and I know we're comparing a little bit of apples and oranges here because one is not strongly typed and the other is, but the complete absence of any type information at runtime inside TypeScript, and also the kind of arm's length at which you have to deal with the types system if you're trying to do meta level stuff. So, if you actually want to analyze a TypeScript file and use the type information at a meta level, it's actually very difficult. The API is extremely cumbersome, the programmatic API to the TypeScript compiler. Same thing really applies with Babel. One of the things that I love, absolutely love about Clojure and really any dialect of Lisp is how close you are to be able to make meta level transforms on any syntax because you can treat any program as just data. So, every Clojure program is a Clojure AST. The data structure and the evaluation of that data structure are one and the same, or they're always close at hand. Is there something similar like this for this toolchain where, let's say I've got a set of types representing a state and I want a set of functions that transition from one state to the other. And I want to say, look at this declaration of a state machine and I want to render a SVG graph showing the state transitions where I have one state for each member of the type union and then a function showing an arrow. I want to draw an arrow that shows the input and the output for each function transition. So, if I've got the type of the input and the type of the output, I can then draw an arrow. It's very easy for me to imagine doing that in a functional language that's a dialect of Lisp. Very difficult for me to imagine doing it in TypeScript. Are there tools for operating with the type system at the compiler level rather than the runtime level?

MARCEL: Yes, there are, absolutely. That is a whole meta-programming sector of this, which is very important for things like Jane Street's huge reliance on OCaml. But that is a kind of language extension which tries to make interfacing with the types and the compiler much more friendly, called PPX, which lets you build extensions on the language in a very predictable way, and then ship them and share them with anyone who needs them. For example, one PPX that's very popular in the ReasonML web world is this GraphQL PPX. It actually converts it into the correct typings that will have to be for ReasonML and checks them as you go, rather than having a separate compiler step, as you might have to do with something like a relay compiler where it checks your thing, asks the TypeScript compiler, "Hey, does this match you what you're expecting of me?" Then come back to the user and say, "No, that's wrong." Here, we're putting an understanding of the GraphQL schema definition language directly into its own compilation chain.

CHARLES: Okay, yeah. And what is that called again?

MARCEL: This is called PPX, and I can't remember what it stands for.

[Laughter]

MARCEL: It was something unusual. I think it's something like something, something extension. But everyone just calls them PPX. I did once know and I remember thinking, "That's ridiculous." And then I promptly forgot.

CHARLES: So, it's kind of like a macro system, or it allows you to work with the syntax directly.

MARCEL: Yeah. And therefore, you end up having to do -- some of the more complex PPXs do some very, very interesting meta-programming based on types in the compilation toolchain.

CHARLES: Okay. That is really, really exciting.

SHANE: Pre-processor extensions.

CHARLES: Pre-processor extensions.

SHANE: [Inaudible]

CHARLES: I mean, that's good to know. Although pre-processor is an unfortunate term. I'm scarred by the C++ pre-processor or the M4 pre-processor, I guess, which is used in C and C++. But I get it. Before we move in to talking about repkgs, is there anything else that we definitely need to call out as being super killer about Reason or that anyone should know, things you're just dying to let folks know something you always lead with when you give a talk on Reason?

MARCEL: I think we've covered most of the score points, which is things like speed, things like reducing your reliance on other parts of the toolchain. One of the nice things is that, which I've mentioned is that you don't need all these things like Prettier, which was also built off Reason's refmt, ESLint or something, because they're all just one mega compiler, one binary to work around. Often, you'll have loads of CI/CD issues or issues on your personal computer because some part [inaudible] out of whack because our toolchain is a loosely coherent set of packages that we marshal along. But here, it all comes in one package. We have the interop, which is nice. We have the syntactic positiveness. The fact we don't really have to do much actual typing, which is great and just kind of falls out of the way you write code, which is nice. And I think that's mostly it. I mean, it means you can do really cool things, like you have type safe CSS because of the syntax extension I mentioned earlier. So, you don't have to have any variance if you don't want that to be.

CHARLES: Okay. Man, I'm sold. I actually am. I'm seriously excited.

MARCEL: [Inaudible]. It does have [crosstalk].

CHARLES: Okay, yeah. That's actually a good point. Because it sounds really awesome, and yet not many code bases use Reason. Why is that? Why are we not using Reason today?

MARCEL: That's a great question. Why aren't we using? Because people are cowards.

[Laughter]

MARCEL: I do think to some degree, I have worked a lot of languages that are incrementally adopted from or a lot of languages that have taken adoption slowly. And one thing I have found that is really amazingly important is for it to be something similar to what people currently use. We like to think of ourselves as technologists who are forward thinking and want to learn new ways to doing things real time. But personal experience says that's untrue. We are like everyone else. We like what's familiar and things we already know. We don't like the idea of feeling junior again when we already feel confident in our way of doing things. One of the best examples of this is a language I used to write a lot in is Elixir. Elixir is based on Erlang, which has been powering telephony systems for older than I am. And I'm getting pretty old at this point. So this is a highly full-tolerant language made for distributed systems. And that become more and more relevant nowadays because as we've come from personal computing backup to the cloud where we need full tolerance and distributed systems, it's an almost perfect candidate. But it didn't really have any adoption until someone wrote a new way of doing Erlang called Elixir. Elixir was made to look a lot like Ruby. And that alongside with the WhatsApp acquisition because no one cared about Erlang until WhatsApp was bought for $19 billion. Then I thought like, "Wow, maybe this is the way of getting bought out by a large company." But that aspect aside, it made it much more approachable. And of course, there's a really huge amount of people out there who write in Ruby, and they wanted something just like a little bit better. So, Elixir had been a much easier adoption process in at least the London startup scene compared to Erlang itself, which, of course, is equally capable but just looks more alien.

SHANE: Yeah.

CHARLES: Yeah.

MARCEL: So, I think we are only slowly getting to the point of having Reason be approachable enough. I think there are still definitely work to be done on a few key points. The story of async/await, you can do it. There's a ton of PPXs for it, but there's not one blast path. There needs to be a very streamlined documentation, like a streamlined, centralized place [inaudible] get started with projects easily where they can be effective quickly and where they can dunk on their friends on Twitter without needing that much experience.

TypeScript, on the other hand, has been very popular because you can adopt it very slowly and you can essentially be using a "TypeScript" of almost none of their features or safety because you could [inaudible] enough and any is the [inaudible] of a code base.

[Laughter]

MARCEL: But once they have it in there, it taints the tree of type understanding because everything has a relation inside, AST. I think Reason still is a little bit too unapproachable for use and it needs to have some of these things like the async story ironed out. While the errors are generally much better than TypeScript because they're going on a sort of Elm approach. If you ever use Elm, it is a wonderful copilot for getting you to where you need to go as long as where you need to go is a web app, because it's not a generic language. And these things combined and the lack of visible momentum, because a lot of this work is done, perhaps not in the open as much as it should be, means that I think it just hasn't got the speed because people do want to use what's popular. And that's not necessarily a bad thing. But community matters and community leads to Stack Overflow posts, which leads to documentation, which leads to help and reassurance that people are doing the right thing. People are often declaring, I think people, it can be seen on Twitter. People often declare technologies is dead. For example, when some Facebook libraries move from Flow to TypeScript, they both declared that, I guess, flow is over. The reality is flow is still the majority use type system within Facebook. It's just for some very external projects, that I would love as a contributor, therefore it wouldn't be nice of them when you use TypeScript. But it continues to be developed, continues to be what they write React in, as well as nearly all of the internal things that they ship.

And in many ways, Flow is a much better type system. It's not quite type sound, but it's much better. It'll force you to be correct, but the tool is not quite as good. And because it forces you to change a lot of things at once, it just was much harder to pick up as compared to TypeScript, which basically lets you get away with anything. And one might argue, what's the point then? And the point is that one can say [inaudible] TypeScript.

CHARLES: The point is to be viral.

MARCEL: And it's important to also note that the TypeScript integration in [VS Code] is great. I think it's really wonderful. One of the things I've always struggled with was having really resource intensive work as I work in the background, always checking files, and that led to a lot of frustration. The tooling story and documentation story and the on-boarding story of TypeScript is wonderful, even if and it may have slightly biased position of having used a large number of type systems, I think TypeScript is not quite as useful as some of the options out there. They really nailed the things that drive adoption. And ReasonML, much like PureScript or whatever else your favorite language happens to be, which probably is very good, the hard part is doing the people part, not the software part. Much like the Haskell approach, and this might be minimizing the Haskell community, so I apologize. But I have often gotten the impression that there is this idea that if a language is just good enough, people will flock to it naturally. If you build it, they will come. Which I think is not actually said on the movie, but it is the common misinterpretation, much with, "Luke, I am your father." And I think that simply isn't true. You really need to do a lot of community outreach and it can take a long time.

TypeScript has been around for a decade now, but it only really gained prominence in the last three-ish years to a degree where people would use it almost by default. And a lot of these rough edges have to be sanded out with ReasonML. And if it gets dark, there's always that fear. If you're going to go to your friends and say, "Hey, we just use ReasonML," and then they hit a frustration or some strange bug or something they can't [inaudible] in Google, you're on the hook for that. So, you have to have a lot of confidence to go to your peers or to your client and go, "Hey, can we use this boutique compile to JavaScript option," when the safe choice is always TypeScript. And honestly, it may well be the correct choice for the majority of cases.

CHARLES: Yeah, but I do think it builds well for the future of Reason. I think it does seem to be put together a little bit better, I mean, certainly than PureScript or some of the other ML-based languages that I played around with, just in terms of the marketing. I'm not saying anything about the technical capability of the language. And it is, I think honestly, the biggest problem with flow right now is that I think it might actually be dead because it doesn't differentiate itself enough from TypeScript. So, while it might be used internally in Facebook and stay alive in that way, and I don't want to spend too much time trying to conjecture about the future of these things, but at least externally, it doesn't seem like it's much of a differentiation, whereas something like Reason really is. It's something different. And that's important in terms of adoption in five years, 10 years, things like that. Maybe not. Anyway.

MARCEL: Yeah. I think that's a very fair observation. You're not going to get anywhere unless it's efficiently better. I remember, back in the Angular dominant days, the only reason people has picked out React because it's significantly better. Things that are only marginally better, people won't bother spending the switching energy for. So, often with projects like [Preact], for example, just say it'll be a slightly smaller bundle size. But people aren't going to switch all their tooling or all their knowledge and all of their risk profile for something that's only slightly bit better. You have to really excel for people to take notice. You have to do something different for that technology to be adopted. And in React's case, what it could do is, unlike all the things it can knockout in Angular. It could be easily understood on a simple level to get basic things going because you have to understand the whole framework. And it was relatively performant, which was a really big problem back in the Angular 1X era, and that really differentiated it.

CHARLES: Yeah, I know. It's the quantum leaps that end up being able to adopt from zero. Otherwise, it's all incrementalism all the way. So, I wanted to talk a little bit about the experience of working on an actual code base with Reason and solving certain levels of problems with it and things that might be particularly suited or ill-suited for solving the problems. Shane, you actually have been developing a program called repkgs, which we got a little bit of a preview in kind of one-off way where we were going to be releasing a bunch of JavaScript packages on the world. And you ran this and you uncovered a whole slew of dependency issues with our packages that would have caused them to break out in the wild. And it was very, very helpful. And I wish we could honestly run it again and again as part of our CI pipeline. So, you've got to release it at some point. I don't know if you have in the interim, but maybe you could talk a little bit about what repkgs is and the choice to use Reason there.

SHANE: Sure. Repkgs is my take on making a tool for not just monorepos but focus on monorepos, making a tool to help validate your packages before you publish them. And the focus is definitely on monorepos, but it also works just like a normal single repo. This start off as just a general monorepo tool. You can run actions. You can get a list of your packages. But there are so many tools out there. I didn't want this to be a competition for, say, lerna or yarn workspaces because there's enough competition in that space. And I didn't see a ton of competition in the space of, is what I'm about to publish going to actually work. Because most tests run against source files and there's almost no common workflow that builds the package as like an artifact and then tries to install it and then runs new tests. It's just my source work. Your source files work, that's great. And you compile them, say you're using TypeScript or even Babel, you're compiling often into a disk folder or from TypeScript to JavaScript. So, the extensions are changing.

There's so many little changes that happen between a moment of my tests say this is going to work and then it actually going into npm. So, this is false in that space where it tries to tell you right before you hit publish, run these checks and then confirm that what you're about to do is what you think you're going to do. And this came about because previously, like five years ago when yarn had just come out, I had made another monorepo tool called knit, which was very magical. And it basically ran through all of your code to find all your dependencies for you. I think it's still a pretty cool project, but it competed directly with lerna. And with lerna, it was such a behemoth, had so much backing. I didn't want to try and do that again, even though I think there's some ideas in it that were really powerful.

One of those ideas was walking through source code to determine the shape of the project and what dependencies are needed. And so, I took that idea. I think that was the interesting idea that knit had, and I just kind of focused on that. And that's how repkgs came about. It crawls through your code, it crawls through your package manifest, and it will try and find all the things that are about to break on you. That's just an overview of repkgs.

And my reason I picked ReasonML is that was just a thing that I wanted to do.

[Laughter]

SHANE: Honestly.

CHARLES: That's a perfectly valid reason.

SHANE: Yes.

CHARLES: Some might say the only reason.

SHANE: I think it's the only real reason. Everything else is just to justify that. Like I said earlier, I looked actually into using ClojureScript for this, but I liked the output of ReasonML and BuckleScript because I was thinking about making some smaller packages that could be reused and BuckleScript felt like a better solution. And I worked on this project for about three months. And in that process, the first month, I used Reason as a BuckleScript. I was compiling to JavaScript and running on Node. And that process was very much a learning process.

CHARLES: Wait. You were writing in Reason and then compiling to what?

SHANE: Over the three months, the first month I wrote, it was always in Reason syntax but I wrote using the BuckleScript compiler to compile down to JavaScript.

CHARLES: Oh, so wait. I feel like one of the things that Reason needs to do is have like a big diagram on the home page that shows the toolchain because I'm having difficulty getting my head around all the different moving parts.

MARCEL: I have made this diagram several times.

[Laughter]

MARCEL: Maybe I should just open up PR on the home page again to put out for me.

SHANE: ReasonML is the syntax and then BuckleScript is what turns that into JavaScript. But there's also Reason Native which will turn it into the OCaml [inaudible], which you can run natively.

CHARLES: Okay.

SHANE: So, the difference is it's not actually not all BuckleScript-supported ReasonML will compile down to Native OCaml. It's not ReasonML, and then you just flip out the output. Sometimes, you have to make changes. So, it is kind of complicated and a little confusing. Basically, the first month I was using, it was going to run on Node. My output was running on Node. And in the next month, I had it running as Native compiled. And then the third month, I went back to Node.

CHARLES: Okay. That's awesome, by the way.

SHANE: Yeah. Well, I can explain why. The first month I was just learning BuckleScript and ReasonML, and that's when I was getting stuck but stuck in a way of I kind of felt like it was my fault that I just didn't know the language well enough. And I could usually see where I was trying to go. I just knew I had to figure out how this syntax worked or how do these modules work. So, I felt like I was slowly but surely making progress, except when I would run into a problem that was very Node-specific. Because if you Google BuckleScript, ReasonML, it will immediately take you to React. That is by far the biggest focus of BuckleScript is React.

CHARLES: Right.

SHANE: So, finding answers to my questions that were Node-related, like interacting with filesystem and how do I do this, and all the Node binding, it isn't fully complete. It has only a couple of the methods on all of them. So, anything Node-related, I found pretty frustrating to deal with. And there was a lot of me just kind of like 'I guess I'll figure this out on my own' sort of feeling. And I got to the point where I was thinking, "I'm running this locally. It's never going to run on a browser." And Reason has this cool option where I can compile to Native code. So, I rewrote everything. I didn't try and convert it because it didn't really convert the way I wanted it to because I was using a lot of Node bindings in my original code. So, I just rewrote everything.

CHARLES: Okay. So, when you were outputting a Native binary from your Reason, are you literally using the operating system native libraries like, what is it like? The stdlib on Unix to get access to stderr and stdout and all that stuff?

SHANE: I think that is what's being used. You do have to compile to the platform so you don't just make one binary. It's like you have to build one for Windows, for OSX. I didn't go that deep into it because when I made the transition, I was very Node heavy. And then when I transitioned over to Native, I rebuilt everything. And that process actually was not fun at all. That month was a pretty terrible month of me working on this. There are a few libraries that have been around for a while, if you want to do a commit, [inaudible] arguments or reading file system or work with the operating system.

There's one guy, I can't remember his name, but he seems to do everything. [Inaudible] forever and they work pretty well. But there's not a ton of examples. For a language that's so old, I found it extremely hard to find working examples to help me. So when I got stuck, oftentimes I was just stuck. Just like dead in the water for days and days, just trying to work through these issues myself which I found very frustrating. One thing I do a lot of in this application is I read the file system and I use like globstars to read through directories. And all of the Node packages have this supported, like the one globstar with two globstars means it's recursive. In OCaml, I couldn't find that anywhere. So just the basic here is a path with globstars in it, and it means go through all directories. That wasn't a thing that I could do. It just wasn't there. There's an OCaml-re which is regular expressions and it had some path stuff but it didn't support that. And that was like the main one that people use. It didn't support it.

There's another tool called Dune, which is their package builder. And I had to use their library for a while, but I don't think that's supported in the same way. I basically had to build my own, and that was not the best. I don't want to have to build my own regular expression parser. And basically, it's very frustrating.

MARCEL: This is actually an endemic problem inside all the OCaml communities because OCaml has a bunch of factions. Not that they're at war or competitive, it's just they have their own kingdoms in which they find OCaml resource. Some of them are very academic, like this team in France or very financial like Jane Street, who has their own library for basically everything.

One of my friends, [Rizo] is a huge OCaml fan. He is the more competent technical part of the Reason London experience, while I am the razzle dazzle. He has continuously talked about the things that there are four to eight standard libraries and there isn't a community centralized documentation system and it's all a bunch of IRC servers where people in the know talk to each other and decide what's going to happen with the language. And this is definitely something that hopefully Reason can help with, because it will highlight the fact that if you want mass adoption or adoption by more people, these community items are required because very few people will power through frustration in the same way that Shane did.

SHANE: Yeah. I made a decision that I was going to figure it out. And I, multiple times, just said I am done with programming forever, and I just closed my computer and walked away for a day. I couldn't imagine anyone doing that for work though.

CHARLES: But you went back then to Node.

SHANE: Yeah.

CHARLES: But at the same time, this is kind of how like the reason we have that in Node like the [inaudible] is because back in 2009, that's what the Node ecosystem was. If you wanted something to actually recurse through a directory, you had to build all that yourself.

SHANE: Yeah. That's the happy ending to the story is when I went back to Node, I actually understood the language a lot better. And I was able to pretty much solve all the issues I had that first month. Instead of learning the language or learning how to check the file system or getting frustrated, I could just use the types and really build out what I was trying to express using modules, using types. And the rebuild when I went back to BuckleScript was a really pleasant experience. That really sold me on BuckleScript and ReasonML.

MARCEL: [Inaudible], we have all the knowledge you need to tackle the enemy you had a problem with it the first quartet of the hero's journey.

SHANE: Yeah.

CHARLES: It's a validating story because if you are able to spend the work to learn how to make the hard thing easy, then you can do the easy thing because that was hard previously. Doing the hard thing is now easy.

MARCEL: I think also, to Charles's point, there is now a library called reason-nodejs which came out fairly recently that attempts to, I think, tackle many of these Node problems. It even has a file system example on the Read Me. You may be correct that a lot of these frustrations will eventually get solved by people writing packages that we then just consume and don't think twice about.

CHARLES: Yep. All right. Well, I think we're almost there. Gentlemen, it has been a journey. I actually am pretty excited. There's a couple of things that I want to try now. As you guys know, I've been fooling around a lot with structure concurrency and knowing that the async/await story isn't quite pinned down in Reason makes me want to try and implement a more general structured concurrency story there. Just give it a stab. And in knowing that there are these PPXs that you can extend the syntax is really exciting because one of the frustrations of trying to do that in TypeScript has been you're very limited in the syntax that you can do. You've kind of got to work with what you've got. And the typing around generators and co-routines is just not great. And it's not going to get better unless you can convince the people at Microsoft to do something about it. But it sounds like there's actually a way forward, which is ultimately the power of having these syntax transforms, which is exciting. So, if I ever can find some spare time, I am not even lying, I want to dedicate some cycles to this.

MARCEL: There's a library called bs-let, which is a PPX that tends to make a very general, almost monadic approach to awaiting stories in JavaScript, which is worth a read if you are interested in that sort of thing.

CHARLES: Unfortunately, I am. Oh, and they've got letPlus and letStar. All right. Anyhow, thank you all for stopping by. Everybody, go out there and Reason away. And we will see everybody next time.

MARCEL: All right. Bye for now.

CHARLES: Thank you for listening. If you or someone you know has something to say about building user interfaces that simply must be heard, please get in touch with us. We can be found on Twitter at @thefrontside or over just plain old email at contact@frontside.io. Thanks, and see you next time.


Please join us in these conversations! If you or someone you know would be a perfect guest, please get in touch with us at contact@frontside.io. Our goal is to get people thinking on the platform level which includes tooling, internalization, state management, routing, upgrade, and the data layer.

This show was produced by Mandy Moore, aka @therubyrep of DevReps, LLC.