CORECURSIVE #048

The Reason For Types

ReasonML and JavaScript With Jared Forsyth

The Reason For Types

Adam talked to Jared Forsyth about his journey from untyped javascript to using flow and eventually reasonml.

Transcript

Note: This podcast is designed to be heard. If you are able, we strongly encourage you to listen to the audio, which includes emphasis that’s not on the page

Intro

Adam: Hello. This is Adam Gordon Bell. Join me as I learn about building software. This is CoRecursive.

All right. I have been confused about something. I really like having static type information when I code. When I think about building something, I think about defining types, writing things to map from my one type to my other. That’s how I design in my head when I’m thinking about how to solve a problem.

However, smart people, talented people that I know view things very differently. There are skilled people who would leave their job before using a language with static types. So I emailed this guy.

Jared: I’m Jared Forsyth. I am a software developer at Khan Academy.

Adam: Jared started in I was in one camp and moved to the other, sort of, because now he’s all about inferred types and maybe that’s the best of both worlds, but I’ll let him explain.

I Was Against Types

Jared: I’ll admit. I was definitely scarred by Java and C++ in an intro to programming class and I never want to look at types again camp. My first language was Python and followed closely by JavaScript. And so I was loving the loosey-goosey scripting language.

My first experience of using types in JavaScript, I was like, “Oh, is this going to be terrible because there’s so much overhead and so much-“

Because in Java and C++, you have to write types for literally everything, right? You declared a variable. It has to have an explicit type and a function explicit type. It was all over the place.

And it was actually really refreshing in Flow and TypeScript and also a reason which we’ll talk about where so much of the typing can be inferred for you.

So you declare a function, you use it one place and from the contents of the function, the type system can discover, Oh, they’re adding this variable to another. Those are going to be numbers or strings depending. And you can be really clever about that so that you don’t have to be writing types everywhere, but you do still get the checking and you can hover over a variable to discover what’s the type that was inferred for this which is super nice.

Adam: There must have been some moment where you were like, “Oh, this thing got caught.” Or “Hey, I can go to definition.” Or something where you were like, “Oh, the light bulb turns on.”

Jared: The thing that really has made it so that I never want to go back is the way that having an explicit type system changes the way you think about code and where you define explicitly this is the shape of the data that I’m going to be dealing with. Here are the data structures, I’m going to lay those out, and then I can write functions that will manipulate those.

And it results in much better organized code and is just such a help in me being able to process new code that I’m reading or code that I wrote two weeks ago and I’ve forgotten entirely about.

And that was kind of the, wow, this is essential because like, “Oh, it caught a bug for me. That was nice, but I’ll just not write that bug next time.”

Adam: Yeah.

Jared: But here are new tools for thought. Here are new tools for writing high quality code where now anytime I’m starting something in JavaScript, I add Flow to it.

Types Are Not A Personal Taste Thing

Adam: So I had a previous interview with DHH, created Ruby on Rails. And I think he said he doesn’t get it. He’s like, “I get some people who really want types. I don’t want them. It’s like a personal taste thing.” So you’ve made this transition. So I’m trying to figure out. There’s a thought process or a perspective that needs to change or am I just missing something? I don’t know.

Jared: No, it’s true. And I’ve heard also Rich Hickey, the creator of Clojure, is famously skeptical about types, and in fact has come up with a different thing that he uses in place of types, that schema and it’s runtime schema checking, but it’s not really a type system.

So I’ve also listened to him discoursing on why types are just a matter of taste. And so I’m familiar with that perspective. I think it’s maybe a cop out to say that we’re not talking about the same things, but I think it might be a matter of misperception where, like I said before, I was sold on static typing. I viewed it as this is going to be a lot of manual labor and yes, maybe it will find some bugs for me, but I can write unit tests and that’s fine. Certainly the Ruby community is all in on unit tests and we’re going to do exhaustive testing and that will be great.

But it’s possible that you’d be able to find some programmers out there that would say commenting your code is a matter of taste. But I think in professional development, it’s pretty standard that, yeah, you want some doc comments to describe at a higher level, at a human level, here’s what this class is going to be doing. Here’s what this general group of functions is responsible for.

Some people take those comments and they’re like, “Oh, well let’s add Javadoc to these comments.” And in JavaScript, if you add Javadoc style comments, then yes, Lint can do some things or Google’s Closure Compiler can do some things.

But the issue is those comments can go stale. If you’re like, “Oh, this argument is this thing.” or “There are these arguments.”

And type annotations to functions are like comments that can’t go stale. And they add so much to the [inaudible 00:05:11] ability of a code base.

It’s possible that I’m too far removed from when I didn’t like type systems to be entirely useful to you. But these days, I see code bases that were written without regard to types, digging into the dynamism that’s possible with JavaScript and are just like, “We’re going to add a bunch of random attributes to this object and there’s no way to know at any given time which attributes [inaudible 00:05:39] to it yet.”

And maybe I should read some of DHH’s code, but I would guess that the code that he’s writing is easy to type. It’s not like, “Oh yeah, I love to have functions that take a ton of different types of arguments depending on how you call it.” No, that’s actually just bad practice generally.

So having a type checker helps you read other people’s code and especially as the size of the team gets larger, keeping everyone on board is so much easier if there’s something that’s enforcing those coding practices.

Adam: It’s like the TypeScript slogan about scaling.

Jared: Right.

Adam: They’re talking about like scaling a team, actually. Not really in terms of the-

Jared: Exactly.

Adam: … Whatever amount of data you’re going to throw at it.

Defensive Programming

Jared: I can’t tell you how many times I… I guess I said this already, but looking at a function in untyped JavaScript, you’re like, “Where does this value even come from? And what guarantees do I have about it? Zero. I have zero guarantees.”

So then, another direction to take it is I’m going to do a million dynamic checks at the top of this function. And this is what we had in 2013, 2014 JavaScript.

Adam: Check the number of arguments and the-

Jared: Yeah. We’re going to check the number of arguments. We’re going to do a bunch of type of checks to be like, “Okay, make sure this is a string and this is a number and this is an object that has these attributes.”

That’s so much code that is… It’s defensive programming. We’ve got a better way now and it’s fantastic.

Adam: Yeah. That makes sense. If you think of that, the type checker is something just doing all that defensive stuff for you.

Jared: Right.

Adam: Yeah. What about prop types in React?

Jared: Yeah, prop types were a gateway drug, I guess. The creator of React, Jordan Walke, is also the creator of Reason, big into Ocaml, big into types. And one of React’s big selling points early on is this is a framework that can scale because it dials in hard on encapsulation so these components can be reused in comparison to Angular at the time with the dynamic scoping stuff that was going on there made it moderately dangerous to reuse code.

React was really dialing in on let’s make these things were usable. And in order to really deliver on that promise, especially with a team that’s large, you need to be doing this defensive programming. So react prop types built in all of those texts for you.

And then a couple of years later along came Flow, which was like, “We can do this comprehensively for all your JavaScript, not just for your React components.”

Adam: Today’s episode of CoRecursive is sponsored by Springboard. If you want to learn how to write machine learning algorithms, or if you want hands on experience deploying a machine learning model into production, or if you want to learn how to build and deploy a deep learning prototype, check out their Machine Learning Engineering Career Track.

When you join this program, you’ll be paired with a machine learning expert who provides one-on-one mentorship throughout the course. This program is designed for software engineers. So you must have at least one year of experience in a modern programming language like Java or C++ or Python.

Now here’s the cool part. CoRecursive is exclusively offering 20 scholarships of $500 to eligible applicants. Make sure you use code AI Springboard when you enroll. I’ll put a link in the show notes as well. The 20 scholarships are awarded on a first come first serve basis. Check it out. See if you are eligible. Applying is free and it only takes 10 minutes. Thank you, Springboard.

And then where does reason come into this?

ReasonML

Jared: So Reason is built on OCaml. So OCaml is one of those languages that routinely makes it on to you got to learn these five languages to change the way you think about code. There’s going to be probably Clojure on there or some other Lisp and there’s going to be Haskell and there’s going to be OCaml. It’s something like 25 years old, been around for a really long time.

And a lot of the modern, cool languages are very much inspired by ML and Ocaml. So Rust, Swift, Scala, these things are drawing on the type system that OCaml, and also to some extent, Haskell have.

So Reason is an attempt to make OCaml more [inaudible 00:09:47] to JavaScript developers. That’s really one way to pitch it. Because there’s so much tied up in syntax that for many people myself included at the beginning, I was looking at Haskell. I was looking at Elm.

Elm is a very cool language, but the syntax is so foreign, it takes me so long to read a snippet of code because I just don’t know how to parse it. I’ve got to be like, “Okay, what’s the precedence here? How do we deal with… Is this getting called with arguments or is it just getting passed?”

If you just slap some parentheses and curly braces, it just feels so much more familiar and that’s essentially what Reason is. It’s building a community, bringing in JavaScript developers.

And fairly early on, Reason also got very tied to BuckleScript, which is a compiler that will take your OCaml code and turn it into [inaudible 00:10:29] and readable JavaScript.

So these days, the Reason ecosystem is a way to write something that compiles a JavaScript, but then has a rock solid type system and has also taken a middle ground approach on a number of maybe you’d say purity questions.

It supports mutation if you want it. You can do an imperative style in cases. And sometimes there are algorithms where it’s like doing this the FP way is just going to be orders of magnitude slower. So I’m going to do a mutation here. It’s fine.

Me starting out in Reason, I felt very comforted by the fact that I could reach to and do something that the messy way, the JavaScript way, and just get the function written so I can move on with my life. And then I could go back and write it better with more safety guarantees, that kind of thing. I don’t know how well I described Reason for you, but that’s what it is.

Adam: There’s a lot to unpack there. So it sounds like OCaml could compile to JavaScript. Is that right?

Reason Backend

Jared: Yeah. It’s got a bunch of backends. So it’ll compile to native desktop also to Android iOS JavaScript.

Adam: But then Reason is not OCaml strictly speaking. It’s a different language, right?

Jared: It depends on what you call a language. Is Elixir a different language from Erlang, if you’re familiar with those two?

Adam: Yes.

Jared: Alexa is literally just a new syntax for Erlang. maybe I think it has a new standard library. But is Scala a different language from Java? They both run on a JVM. Scala is probably arguably more of a different language than Reason is because Reason uses the exact same compiler as OCaml does. But it is a new syntax and tool chain is often what I call it for Ocaml.

Adam: So you have a OCaml compiler, you take off the front, and you put some new syntax on the back. And then you take off the back and you put JavaScript in there.

Jared: That’s right.

Adam: And then [inaudible 00:12:15] you removed everything or?

Jared: The type system is the same.

Adam: Oh, okay. Yeah.

Jared: And that’s really the bones of if you look at the OCaml compiler, the compiler itself has a number of… There’s the lexer, there’s the parser, there’s the type checker, and then there’s the thing that generates the assembly. And it’s really the only, the last bit. Generally the assembly change it while there’s a couple other internal steps. But there’s a lot that is shared and that is, I think, the things that make OCaml great. The language semantics, if you will, the module system, the function system, all of that is the same.

Adam: Ah, I see. I think I get what you’re saying. It’s not just the syntax that’s changed. It’s like the syntax has changed at a very surface level to make it more Javascripty. It’s still-

Jared: Right. Yeah. So literally you could go through. Initially the changes to the parser, it was based on the OCaml parser. And it was like, “Let’s just switch out. Let’s add some semi-colons here and add some parentheses here.”

In the intervening years, it’s gotten further from that, but it is still based on OCaml parser and most of it is shared.

Adam: Yeah. And so we started off talking about types. So it’s the exciting bit of Reason?

Inferred Types

Jared: Yeah. Especially coming from JavaScript and also coming from Flow and TypeScript, Reason and OCaml has an almost entirely inferred type system.

So whereas with TypeScript and Flow, in order to really get the advantages from it, you need to write function signatures, or at least for the exported functions and [inaudible 00:13:45] write your interfaces and stuff.

But with Reason, I only write data types. I create the data type. And this is, like I was saying before, when I’m thinking about a problem, I will write out the shape of the data and then I just use it.

And then I just use the variables and everything is inferred, but unlike Flow and TypeScript, there’s no any that would just be pervasive throughout [inaudible 00:14:04]. It’s like I can have confidence that it really has my back.

And the JavaScript compiler for OCaml is lightning fast. That’s one of the other things about the OCaml system in general, is generally been written for speed. So if you’re used to Scala compile times or Rust compile towns or anything like that, you’ll just be blown away. It is milliseconds to do a full rebuild of a reasonably large project. If you’ve used a Webpack or Babel, then you’ll be blown away as well.

Adam: Oh, so it might actually be faster than my existing JS.

Jared: Oh. So much faster.

Adam: Oh wow.

Jared: Because the JS build system is run in JavaScript and JavaScript has a 200 millisecond startup time. To run node, you’re giving away 200 milliseconds for every process. And your Reason build chain can have completed 10 times in that amount of time.

Adam: Oh wow. I wouldn’t have expected that. That’s impressive. So you mentioned laying out a data type and then using that. Do you have an example that might help us understand?

Jared: Let’s see. We could talk to do MVC. What’s your to-do item shape? It’s going to have a title. That’s going to have an author. Maybe it’s going to have a Boolean for whether it’s been completed.

Adam: Yeah. So I define a to-do item. It has some properties. And then if it were TypeScript, then my functions that dealt with that, I would just put type annotations on them.

Jared: Right.

Adam: And you’re saying, I don’t have to do that.

Jared: No. Yeah. You create the object somewhere. And again, Reason tries to be as familiar to JavaScript developers as possible so it’ll look like the same object, syntax. In Reason, they’re called records instead of objects because of complicated past. But you just create the object literal and then pass it around. You can access attributes and all of that and you don’t have to be dropping annotations anytime you want to use it.

Adam: So can I if I want to?

Jared: Certainly. Yeah, for the purposes of reading code. Especially if you’re reading it on GitHub, it’s nice to have the annotations there because you don’t have the hover for type kind of stuff.

Adam: Nice. What else does Reason have? What else makes it unique?

Reason VS Elm

Jared: I’ve got a different pitch depending on where you’re coming from. If you’ve tried Elm, I could talk about similarities and differences to Elm. For example, Elm has a focus on immutability and sandboxing from JavaScript, where the creators of Elm somewhat justified in this say JavaScript is very dangerous. It does not give you guarantees. And so in order to interact with JavaScript, you need to go through a serialization bridge and we’re going to make that asynchronous. And that will make sure that there’s no way that JavaScript’s unsafety can infect the safety of your Elm program.

I’ve talked to some people that were using Elm, we’re running up against that a lot, and tried Reason, and were very happy about how Reason doesn’t enforce that barrier nearly to the extent. You write your type annotations for what you expect JavaScript to give you and that’s that. You can call the functions synchronously. There’s not a serialization bridge. There’s not nearly as much work to bind to a node module for example.

Now, that comes with unsafety, right? If you expect JavaScript to give you a number and it gives you a string, then you’ve got to run time exception.

Adam: Oh, I see. Yeah. So Elm, they want it to be completely sound so then they lock it down, but it prohibits adoption to a certain extent.

Jared: Right. And it can make some performance things more difficult and some other things… Now, one thing that I love about Elm is that it has narrowed the scope of what it wants to do. This is a language for building UIs.

And it’s phenomenal at that. Because of that, it can make some trade-offs. Generally, you guys are not performance bound. Despite what the demos might suggest, you’re unlikely to be rendering 10,000 elements on a page, or most of us don’t do that in general.

So the trade-offs it has made, I think, are perfectly reasonable. Reason and OCaml are much more of a this is a language that we can use for UIs. We can also use it for servers and for embedded devices. We can use it to build games. And there’s a very cool text editor, native desktop, et cetera, being written in Reason. It’s just such a wide gamut.

And that’s one of the other things that makes me really excited about Reason. I’ve written and shipped a couple of native Android and iOS apps written in Reason. And being able to learn one language and then write it cross platform without having the trade-offs and performance hits that come with React Native with JavaScript on a mobile device, that’s always going to have worse animation performance.

Adam: How are you writing a Android app in Reason?

Jared: That’s right. Yeah. And this is taking advantage of the incredible work that’s been done in the OCaml world, where there’s an OCaml backend for Android, for iOS. So I’m not bringing in NPM libraries to my Android app, but there is a wealth of code that has just been written in pure OCaml or pure Reason. And you can just bring that in.

Adam: Interesting. It’s really exciting. I could see how it could be a limitation to in just you’re spreading yourself very thin if people are using this language to do this and sometimes it’s really great to have a certain domain where people use things and libraries build up and it gathers steam.

Jared: Totally. And that is certainly a limitation. I think Reason’s community has generally coalesced around web development. Reason also has best in class React support. So using React and Reason is better than using React and JavaScript. I mean, React was built for types. It was built with types in mind and JavaScript types are just not going to be as good because Flow and TypeScript are partial type systems. Using it in Reason is a dream. So we’ve got a lot of people doing React and Reason. And then certainly much smaller communities doing game development, doing native development, that kind of thing.

React With ReasonML

Adam: What’s the advantage of React and Reason? What does Reason buy you in the React ecosystem?

Jared: It’s nice that it’s immutable by default. You don’t have to worry that somebody will accidentally have modified the props because they don’t know the conventions of React. There are a lot of things that you can do in JavaScript to completely mess up your React application just by accident, just because JavaScript lets you. Whereas it’s much more tuned in Reason because of the type system and the general program semantics. On top of that, Reason has JSX built in so you can be up and running immediately.

Adam: Did you say the React creator created Reason?

Jared: That’s right. Yeah. Jordan Walke was originator of React and helped by a bunch of other really excellent people. And then he also started the Reason project.

Adam: Oh, very cool. I’m primarily a backend developer. I do a lot of FP stuff and people use that term very generically. And I think at least in my little group, we mean something pretty specific that has to do with types and immutability and composing things. We’re trying to always convince other people that this is super useful.

It’s been a new discovery to me that actually on the front end, people have been figuring this out while I wasn’t looking. I guess React, it seems to have a lot of this spirit, I guess, in it maybe.

Jared: Yes, definitely. That’s actually another good point with Reason and React because React is built very much in an FP mindset and Reason and OCaml are what you might think of as the original FP is OCaml and Haskell. Those are the things that people are drawing from these days. Unless you want untyped FP and then it’s the Lift side of things. But if you want, Reason has immutability, automatic currying of all functions and just generally functions are the way to do things as opposed to classes that encapsulate both data and functionality.

Immutability in ReasonML

Adam: You mentioned immutability. How does that work?

Jared: So the default is just that all attributes on all objects are immutable. You can annotate them as mutable and then you can mutate them. But the default is immutability and structural sharing.

As JavaScript has developed, it’s actually gotten more and more Reason. And so it’s easy to move over because it’s like, “Oh, object spread, I know that. That’s how I do things. And we’ve got map and filter and reduce and all these things.”

Adam: I imagine though, I’m just guessing when I do something with immutable lists and whatever in Scala, to make it performance, there’s a certain implementation. But aren’t we just using the JavaScript built in types like arrays or whatever?

Jared: So Ocaml has arrays and lists. And lists are linked. So if you’re using arrays, they are immutable. And there’s certain cases where you’re writing Reason and arrays make sense. But most of the time I’m just using the default list implementation and the functional methods that go along with it.

Adam: And if I want to use something that outputs a Reason list but from JavaScript, what does it end up looking like

Jared: It will be a linked list. So the BuckleScript internal representation is a JavaScript array with two elements. The first is the contents and the second is the tail and that’ll be another two-element array. So that’ll get boring pretty quickly.

So generally, when you are writing interface code between Reason and JavaScript, you’re converting your list to arrays. But like I said earlier, if you’re interfacing with JavaScript, for the most part, you’re not going to be running into performance intensive applications. You’re not transforming a million items in somebody’s browser.

Adam: No, that’s true.

Jared: Yeah. But there is some trade off things where you’re like, “What’s the best tool for this job?” And there are the hash array maps, try thing that Clojure has that has some cool properties. There are implementations of that for OCaml, but you can bring in that library if you want, but the defaults tend to be good enough, especially as the JavaScript that it’s output, the Reason compiler or the BuckleScript compiler is very performance sensitive and it’s very tuned to take advantage of ways to make JavaScript fast.

Adam: Why would I want something to be immutable?

Jared: Immutability saves you from spooky action at a distance is generally my pitch. There’s so much uncertainty around, I’m doing this thing and I called this function and what if this function completely messes up the object that I pass to it? So I’ve got to clone the object before I hand it in or whatever. Again, defensive programming.

And in a large code base where mutation is the norm, you just have to be looking over your shoulder all the time. Now, in the code bases that I work on at work, immutability is the norm. So I can generally just trust that I don’t have to be worried about somebody changes something out from under me. It would be nicer to have that statically guaranteed by the language system, but we do what we got to do.

Adam: Yeah. So it’s like, you’re working in a world where you just assume immutability. And that generally probably works, right? Because everybody has the same assumption.

Jared: Right. And if you’re using React and you’re using Redux especially, Redux will fail in comical ways if you start mutating objects. So I think these libraries have done a lot to bring immutability as a norm into professional JavaScript development.

Sum Types in ReasonML

Adam: Yeah. What about sum types and algebraic data types?

Jared: Yeah. It’s hard to pitch something that you don’t know you don’t have. [inaudible 00:24:56] So a JavaScript developer is not going to be like, “Oh, I always wanted that.” Because they just use other ways to get around it.

But if you have done any Swift or you have done Scala or Kotlin or REST and you’re like, “Oh, I wish JavaScript had sum types. I wish it had product types.” Then, Reason’s got your back.

So sum type is an enumeration. It’s like a Java enum except it can hold data and different kinds of data and it’s so helpful. There are just so many problems that if you’re trying to do it the JavaScript way, you’ve got to be doing a lot of checks. If you’re used to Flow or TypeScript, they both have sum types called tagged unions where you have an object and one of the keys is the tag that says, “Oh, this is going to be the loading state.” or “This is going to be the loaded state.”

So you already have that, but it’s nicer in Reason to have that built in, to have dedicated syntax for it to make sure that you’re handling all the cases that you need to.

It gets really cool when you’re running a switch statement and you can enumerate over all the different cases. Whereas in JavaScript, switch statements are anemic. They don’t even have separate scope between the different branches of the switch. So you’re just dying inside as you have to come up with different variable names. So they don’t-

Adam: I didn’t know that.

Jared: … Overwrite. Oh, It’s the worst because there’s automatic follow through. And so the scope’s [inaudible 00:26:14].

Adam: I feel like we need to put an example on it.

Jared: Right, yeah.

Adam: What’s a thing that I would do in JavaScript that will get easier with this kind of sum type? I have two different things that are related, but have different data on them. I’m trying to…

Jared: Right. No, I mean the biggest or the most important sum type that we have in our code base that’s using Flow is our loadable data type. This is for anything we fetched from the network that we’re putting in Redux.

And the naive implementation would be on your React component on state, you would have a Boolean that is whether I am loading. So there’s loading which is a Boolean and you would have error which is an optional error and then you would have data, which is optional data.

And so on componentDidMount, you set loading to true and you take off the fetch and then when the fetch comes back, either you set the error to something or the data to something. And then in your render method, you have a couple of these statements. If we’re loading, then render this. Otherwise, if there’s an error, render this. Otherwise, hope you have the data and nobody messed up your state and render with the data.

But having a sum type that enforces, there are three disjoint states. One of them is loading. One of them is loaded with error and one of them is loaded with data. You don’t have to worry that somebody is going to accidentally set both data and error to something. How do you render that? It’s just impossible.

There’s a couple of really good talks about making impossible states unrepresentable where this doesn’t make sense to have loading be true and data be true, unless you’re refreshing, in which case let’s account for that in the data type as opposed to just some coincidence of the way you’ve set things up.

Adam: How would I pull this apart in Reason or Flow for that matter?

Jared: In Reason, you would switch on the loading state and critically, it’s impossible to get anything out of the loading state unless you switch on it. So you can’t make assumptions about you have to switch and say, is this loading or is this loaded or is this failed? And you have to handle all of those cases. I can’t tell you how many bugs in web apps are caused by someone forgetting one of the cases. Oh, I forgot that it could be loading here and it is and so everything’s dead.

Adam: It’s not just web apps. I think it’s the world.

Jared: Right.

Adam: Yeah.

Jared: Yeah. And so having that enforced for you, again, this is another I can offload this from my internal RAM. I don’t have to try and remember what are the cases this can be in. The compiler makes it so you can’t forget.

Adam: I think we talked about why this might be a smoother onboarding than Elm. How would you compare it to TypeScript or Flow?

Jared: Sure. Not to quibble with your word choice, I think Elm has fantastic onboarding because they’ve locked down the problem [inaudible 00:28:53] and it’s an incredible community. I don’t want to turn anyone away from Elm. But if you go to Elm and you’re frustrated by the lack of mutability and the difficulty of interfacing with JavaScript, then maybe come to Reason.

TypeScript vs ReasonML vs ELM

Adam: Yeah. So how would you describe, maybe I don’t have the right words here. How would you describe that distinction?

Jared: So there are a couple of continuums and I would have to pull up on the spectrum from all mutability all the time versus all immutability. All immutability is where Elm is at. You literally can’t mutate anything. And JavaScript is like, there’s no way to guarantee immutability in JavaScript. Well, you can do object.freeze(), but then you have a performance penalty and it’s still a runtime error. So what are you going to do?

And Reason is in the middle. It’s definitely more towards immutability, both by convention and just the easier thing to write is with immutability. But if you need to reach for mutability, you can. And that, to my mind, it’s an easier transition from JavaScript.

Another neat thing that certainly helped my introduction to Reason is you can just dump in a block of JavaScript and be like, “I don’t know how to write this function in Reason. I give up. I’ll just write it in JavaScript. Yes, there are probably typos in it and it’s going to give me type errors and I deserve it.” But then you can call that. It’s just sitting in your Reason code so you can get on with your life. And then later, when it has bugs or when you feel bad about it, you can go back and rewrite it the correct way.

Adam: How does that work? Because you said there’s no Any type. So what happens there?

Jared: So it is inferred to be what you think it should be. You can’t call the function two different ways.

Adam: I see.

Jared: Which is what an Any type would allow you to do. You can only call it one way, but there’s no checking because it’s just, you dumped in JavaScript.

Adam: I see. Whatever you call it as it becomes that.

Jared: Right. And there is technically you can get Any type behavior and sometimes you need that for interacting with the JavaScript function that does literally get called with a dozen different arguments, but it’s a massive code smell and it has to be explicit.

Adam: So Elm is more restrictive. JavaScript is the least restrictive. So where does TypeScript and Flow fit on this continuum?

Jared: So TypeScript and Flow are right next to JavaScript. TypeScript and FLow are doing their darndest to fit a square peg into a round hole and doing a very good job. So if you can’t leave JavaScript, at least at some types. But if you can, why would you stay? Because there’s so much undefined behavior inherent in JavaScript’s runtime and Reason is it feels so much like working in JavaScript, but just without the bad parts. Do you remember, I don’t know if you saw Douglas Crockford’s JavaScript: The Good Parts book. That was 20 pages long or whatever. It’s like the good parts are enforced and you can rely on them.

Adam: Part of the allure of TypeScript, I’m less familiar with Flow, is just how easy it is. You can just rename your files and start there. What’s adoption path to get to Reason?

Jared: Because of the heavy emphasis on JavaScript interrupt being easy, you can start out by just renaming your files. This is especially compelling in the React ecosystem because Reason React component is a React JS component. So you can use a React JS component from Reason and vice versa.

I guess there are two different tax for introducing reason to a JavaScript project. One of them is I’m going to bite off a component and the rest of JavaScript doesn’t have to know.

And the other is I’m going to bite off some gnarly algorithm because I really want some guarantees there and then you might have to do a little bit more data conversion there. But that can often be really big bang for buck where it’s like, this has been a systemic source of bugs and I want to really lock it down kind of thing.

But yeah, as far as you’re using Webpack and whatnot, BuckleScript will produce JavaScript files that’ll be consumed by your whole tool chain if you want to keep doing that.

Adam: So have you made the transition in your day job?

Jared: Not my day job. And there are a number of things that go into that. We recently converted to React Native from native iOS and Android, and we’ve adopted Flow and GraphQL and we’re rewriting our whole backend and go.

So there’s a lot of technical innovation budget that’s been spent the past couple of years. And so it just hasn’t made sense to be like, “Also, let’s ditch JavaScript for this new language.”

So it just depends on your situation because software development is about so much more than the programming language you choose. It is mostly about people and it is incidentally about code. But if I were on a smaller team, five to 10 people, I’d choose Reason in a heartbeat.

JavaScript That Won’t Typecheck

Adam: How often is there JavaScript that can’t be converted because its type is not representable?

Jared: That depends on how strict you are because Flow has Any. And you can just say, “Ah, I’ll type it as Any and I will pay the cost and bugs and developer tears down the line.”

Flow has done some really remarkable things with the type system that allows it to type a lot more of JavaScript than you would expect at the cost of, again still, having to do with JavaScript’s runtime semantics.

Adam: Yeah. It’s a messy world out there I guess. With TypeScript, I know that somebody I was talking to was having problems just because they had a lot of stuff that took a variable number of arguments. It was perfectly acceptable to call it with one or five or whatever. And I don’t think TypeScript, I may be getting the example wrong, but it seemed like it was, yeah, I don’t know what to do with that.

Jared: Yeah. There are libraries, especially libraries written in 2010 that were like, “My favorite thing is to have a function that can be called 11 different ways with these different specific arguments.”

And my response to that is that’s a bad idea. When I’m using these functions, I have to remind myself, okay, is it three arguments or is it four? The behavior changes drastically based on… That’s just not going to be easy to maintain.

Now, if you mean a spread of arguments, like I want to be able to call this with the math.min() function can take any number of numbers, then I’ll just [crosstalk 00:34:44] them. That’s fine. That’s easy to type both in TypeScript and Flow.

But if you’re like for some interesting reason, I want my library to only export one function when it could just as well export 10, I’m like, why are you doing that?

Adam: Yeah. Or curried functions that people have written where you can call it with one argument and then it returns a function that takes the next one, right?

Jared: Yeah. There’s the kind of Scala FP style JavaScript goes in some interesting directions and is harder to type for sure.

Please Let’s Use Types In JavaScript

Adam: So I’m sure somebody listening lives in a big JavaScript code base and is curious about these things. What’s your sales pitch for types in Reason?

Jared: I would say learning types will make you a better JavaScript developer, regardless of whether you start using Flow or TypeScript or Reason, the conventions that a solid static type system enforces are going to make the code just easier to read in general. And because I have learned Reason and because I’ve learned Haskell and various other languages, the JavaScript that I write is different. It is more robust, it is easier to read and it’s just made me a better professional.

Adam: JavaScript devs, dynamic type people listening. What do you think? Do you buy it? Maybe you were just thinking of telling me where to take my static type propaganda. I don’t know. But I hope you find Jared’s perspective interesting.

Go check out ReasonML and Jared’s podcast called Reason Town. There’s a link in the show notes to both. Speaking of show notes, Springboard’s special scholarship program is linked in the show notes. Springboard is my first sponsor. Woo! They reached out to me and the mentorship program they have sound super cool. So check it out. Until next time. Thank you so much for listening.

Support CoRecursive

Hello,
I make CoRecursive because I love it when someone shares the details behind some project, some bug, or some incident with me.

No other podcast was telling stories quite like I wanted to hear.

Right now this is all done by just me and I love doing it, but it's also exhausting.

Recommending the show to others and contributing to this patreon are the biggest things you can do to help out.

Whatever you can do to help, I truly appreciate it!

Thanks! Adam Gordon Bell

Themes
Audio Player
back 15
forward 60s
00:00
00:00
36:35

The Reason For Types