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
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.”
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.
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.
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.
Adam: They’re talking about like scaling a team, actually. Not really in terms of the-
Adam: … Whatever amount of data you’re going to throw at it.
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.
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.
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?
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.
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?”
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.
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?
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.
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.
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?
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.
Adam: Oh, so it might actually be faster than my existing JS.
Jared: Oh. So much faster.
Adam: Oh wow.
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.
Adam: And you’re saying, I don’t have to do that.
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
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.
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.
React With ReasonML
Adam: What’s the advantage of React and Reason? What does Reason buy you in the React ecosystem?
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.
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: No, that’s true.
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.
Sum Types in ReasonML
Adam: Yeah. What about sum types and algebraic data types?
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.
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.
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: 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?
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?
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.
Adam: I see. Whatever you call it as it becomes that.
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?
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.
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 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.
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.”
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?
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.