"Tie your hands to free your mind" is a mantra you hear that applies really well to the constraints that you put on yourself by embracing statically typed languages and functional programming. We're going to hear from various people about their respective visions of typed FP in JS.
Kent C. Dodds
Alright, sweet, those are our sponsors. We're so grateful for them. Because this is a live show and many of you are watching live, you can actually interact with us, it's awesome. So if you go to Twitter and use the hashtag #jsAirQuestion, you can ask us questions and at the end of the show, we'll go through some of those questions.
And then, this is a weekly show, so next week we're gonna be talking about mentoring. I get a lot of questions about people looking for mentors, and I recently got some questions about how you can be a good mentor to kind of solve this problem of people looking for mentors. I'm really excited about next week's show, How to Be a Mentor, with a couple expert mentors, Colt McAnlis, Pam Crayton, Jed Watson and Taras Mankovski. Really excited, it's gonna be great. Cool, so that is that.
Let's go ahead and introduce everybody that we have here. We have a couple panelists, and a bunch of guests. So first, for our panel, we have Dan Abramov.
DAN: Hey there.
KENT: And Brian Lonsdorf.
BRIAN: How's it going?
KENT: And Pam Selle.
KENT: Great, and I'm your host, Kent C. Dodds. And then, for our guests, our distinguished guests, (laughs) we have Jordan Walke.
JORDAN: Hey, thank you for having me on.
KENT: Thank you. And Alfonso Garc°a-Caro.
ALFONSO: Hi there, how're you doing? Thanks for inviting me.
KENT: Sure, sure, and Phil Freeman.
PHIL: Hi there. Yeah, thanks for having me on.
KENT: Yup, and Richard Feldman.
RICHARD: Hey, great to be here.
JORDAN: Yeah, sure. So I'm an engineer at Facebook with Dan and I work on product infrastructure. One of the things that we're responsible for was React, and we continue to work on other cool systems like Relay and React Native. And right now, I'm working on a project called Reason, which is relevant to the topic here. It's a new front end or a new developer experience on top of the OCaml compiler.
KENT: Awesome. Yeah, we're definitely gonna chat about that. Alfonso?
ALFONSO: Hello, yeah. I'm talking from Madrid, and I'm working at (mumbles).com. I'm very happy that Jordan is here because actually we are working on creating some F# type of type provider for GraphQL, this technology created by Facebook. But I would-- (speaking through static)
KENT: Alfonso? I think you're really scratching out really bad, I'm sorry.
ALFONSO: Can you hear me?
KENT: Okay, yeah, that's much better.
ALFONSO: Okay. So you can hear me now?
KENT: Yeah, that's better, thanks. (laughter)
KENT: Awesome, Phil?
PHIL: Sure, yeah. So hi, I'm Phil. I'm based in L.A. and I work on Haskell code a living, that's a (mumbles) networks. And in my spare time, I work on the PureScript compiler. So I started working on PureScript about three years ago, just under three years ago. So I continue to work on the compiler development tasks and then also I have some libraries I maintain. I'll (mumbles) library development, that sort of stuff.
KENT: Great, thanks for your work. And Richard.
KENT: I totally agree. I know that, for some people they're thinking, "Oh sweet, once ES6 ships in all the browsers that I have to support, then I can stop." But honestly, there will always be features of the language that you want to use. And even beyond that, just like you said Richard, you're always gonna be uglifying your code. It's kind of a given, you're gonna have a build chain, and why not just stick a typed functional language compiler in there, in that build chain?
PAM: Maybe. (laughs)
JORDAN: If you're to send them to older browsers, they would just crash when the page loads.
PAM: True, good point.
JORDAN: But there is some relationship between mini classes and stuff like that, you can maybe polyfill those.
RICHARD: I would note that even people who polyfill, typically, I mean, I'm not aware of anyone who doesn't minify their code in production, unless they're working on a toy app or something like that, like people who, it seems like, and maybe this is my ignorance, but my impression is that basically everybody has some compilation step or other, they're just varying degrees of invasive.
PAM: Sure, I could go with that.
BRIAN: So I wanted to throw a quick question out there, I think this is a burning question of a lot of people I work with and people who are skeptical of typed functional languages. What can the types save you from? You mentioned there's not a lot of run time errors, and I think a lot of people think, if they wrote a test, that will cover a lot more ground than a type could. So I'm curious, in particular, PureScript has a lot of constraints you can lay on the types. I'm not as familiar with Elm, but I think it also has those, so I was curious what you can catch, or what type of things you're catching with types.
PHIL: Like you said, PureScript has quite the use of interesting type system features that's of design to help you catch a lot of stuff at compile time, right, a lot of different types of bugs at compile time. And then, you have Haskell and (mumbles) and even further towards this very strongly typed end of the spectrum, and different languages that are wider on the spectrum. But for me, I think for power to weight ratio, it's of the really simple type system features that give you the most, that are the most interesting. In Haskell, we have something like new types, PureScript has something similar. And this allows us to distinguish between things like, "Do I have a string that represents a phone number?" versus "do I have a string that represents an email address?" or something, or different types of strings that are categorized in different ways so I can't mix them up. At compile time, I will be told if I've mixed up a phone and an email address or something.
Another good example of that, I think, is units of measure or something, which is maybe not simple from an implementation point of view, but conceptually simple, that we want to say, "Okay, this number represents seconds or something versus kilograms or something." Patch that in or something. There's all of these very interesting types of features that allow to assert much more interesting things, but, it's sort of simple stuff that's really interesting as well.
And trying to replay for quickly to Brian Lonsdorf, I think it's also great it's a very long debate and I think it's very difficult to settle it down with a couple of words that dynamic programming versus typed programming, I think it's-- because you get used to something so I hear it always that people that love dynamic programming that it takes a lot of time to define your domain model with types. But I think it's true with languages like Java or C#, they have been verbose (mumbles) types. But with a language like Elm or Haskell or PureScript, I think it's much easier to define the types. And for me, of course, you need to get used to that. The types drag you to the right path, so you first define your (mumbles) model and especially we need to use very light-weight tool, and then later you can just let the types drive you. If that makes sense. (laughs)
RICHARD: So to get back to Brian's question of what do types get you on top of tests? Here is how I see it, there's sort of a spectrum and it's a spectrum of guarantees. And what these guarantees get you is, in particular, when you're debugging or re-factoring, answering the question, what is and not possible here? Like what does this code do? So at the one end you have tests and so a test will tell you, if you run your test suites, you can say certain things about your code. So you're trying to hunt down a bug and you're like, "Where could this bug be?" And potentially it can be in any part of your program. So your tests tell you, "Okay, this part it's not this, it's not this, it's not this, it's not--" In each case that's been numerated you can say, "these tests tell me that the bug is not here."
Okay, so let's say you add on a layer of type-checking. So like TypeScript. So now it's going to tell you, "Okay so, my problem is not a type that's matched between these two things. At this point this value has this type," so you've narrowed it down even further on top of your test. You can take that one step further beyond that and say, "Okay, not only do I have that but I also I have these things are constants and these things are immutable. So now I know that not only do these things have these particular types in these particular tests, but also they can't be mutated. So these values that are in this function this time, they can't have changed as a result of other functions being called because they're immutable, because they're constant." And then even one step further beyond that, is saying, "Okay, not only do I have those guarantees but also I have the guarantee that these functions are not doing side effects that are potentially impacting other parts of my programming."
JORDAN: Yeah and just driving that, it kind of sounds like really restrictive, "Oh, this only takes a string, it can't take an int," but all of these languages that we're talking about today, Elm, PureScript, OCaml, Reason, they also provide these mechanisms for you to express what could be accepted. Like it either takes an int or it takes a float, or it takes a string and you model that and express that. So you can expressively describe what is taken, not just what isn't accepted by a function.
KENT: So I think this reminds me of, I don't even know who to attribute this to, but there's the quote, "Tie your hands to free your mind." I think that kind of is the whole mantra of functional programming and immutability and all of this is that, like sure you're kind of giving up a little freedom or you know liberty to kind of do whatever you want, but what's nice about that is everybody else is giving up that same freedom and liberty. And so when you go to look at somebody else's code, you have to hold less in your head. And that's one of the things we're always fighting for when we're developing applications is I only have so much space for state in my head and the less I have to keep in my head to maintain this codebase, the better.
JORDAN: Yeah I totally agree.
PAM: I feel like that's such a weird phrase, Kent. (laughs) Like I guess there's somewhere where I disagree with types being a limitation. Because I think what you're trying to describe with that phrase is constraint-space programming, which is a thing I've heard people talk about. And I'm not sure if that has a relationship to types. So I think, because I would even disagree so far as to say that using a type system is codifying a thing that you were doing anyway. Like when you wrote, choosing the simplest example, when you wrote a function add, you expected to hand it a number, you didn't necessarily expect to hand it a string. And so types are a way to codify the thing that you were already trying to express. Which is not really a constraint, it's actually being more explicit about what you mean.
KENT: Right, I agree that it's more explicit, but there are-- like in functional programming and in typed programming, you do have constraints. Like that's part of the whole idea is this idea of constraints.
PAM: Can you expand on that though?
PAM: Okay, yeah I think that helps.
PHIL: As a producer of libraries, it can kind of seem like it's burdensome to have to sort of start with these constraints, right, but the converse is that as a consumer or somebody trying to use a library, good types and those constraints should also serve as a documentation tool, right? As Richard said, if I see a function from string to edit and somebody else rolled that function, since I'm at the library, I know exactly how I should be expected to use that. I can expect it to work if I use it right a right way. So types would serve as good documentation tool.
BRIAN: I should throw out there, if you're not familiar, you can actually constrain things with your types as well. Say like in your PureScript by example, you can constrain functions that are partial or total. Or you add type constraints in there. So they're kind of related too.
KENT: Yeah Richard, you can go ahead and bring up hiring if you want. (laughs)
So by far the most effective tool we've had for hiring front-end people is using Elm. I'm not kidding, like before that, we went almost two years without making a front-end hire because it's just so hard to find good front-end people. Ever since we've started using Elm, it's almost like people are beating down our door to work here. Like people want to use good tools and good people want to use good tools even more. And so the fact that we're able to say-I mean, we can practically just show up to a conference and say, "Hi, we use Elm in production and we're hiring. And people want to work here."
And it's really surprising because you'd think that, "Oh well, there's a much smaller number of people who know Elm out there." And that's true, but there's a lot of people who want to learn it and who want to use it because they're intrigued by it. And so we don't expect anyone to know Elm on day one but it doesn't take that much to learn, believe it or not, if you're surrounded by people who know Elm. Or if you're reading a good book on it like 'Elm in Action,' shameless plug. (laughter) But it's really true that, you know, as counter-intuitive as it might seem, if you're trying to hire good people, being able to say you're using a really awesome technology is a huge selling point and makes your company really stand out from the crowd.
JORDAN: That's a good point.
ALFONSO: Yeah, I'd like to point out, Phil and Richard have been talking about the side effects. Pam also as well. I think we should distinguish between a pure functional languages , like this coming from Haskell and language maybe in this case maybe Reason, as well as F#, they both come from OCaml. So it's an impure functional programming language, so it means that it allows you to do these kinds of side effects. And even for Fable, for example, you can even do dynamic programming. So F#, we say that it's functional first language but it's not-- you can apply different products with if you needed to.
So it's the same way as when we are talking about dynamic programming, you say, "No, no I want to do things very quickly. I don't want to spend time creating my mine model." So in this case, it's more or less the same as the milistep. You think that maybe something's unique to access the DOM but you need to mutate something. So it's good that you have this feature, but I completely agree with Richard and Phil, that if you take this job and you get excited to go to the completely pure language, I think the chances that you get hours and the work time are much less.
BRIAN: I just want to-- And that's totally right, it's good to know about the distinction there. And I think on-boarding or learning the language is pretty difficult especially in a pure setting. And one of the hardest things, is to actually understand what the compiler is trying to tell you or know how to fix these kind of random type errors. Can anybody speak to, how to learn a language, like a real typed functional language that might be totally different from what they're used to?
PAM: Do you mean-- so Brian, which is your question, like where are some suggestions for someone to start or maybe even just people sharing their personal experience?
ALFONSO: Yeah, Elm has set the standard for compiler-friendly message. Friendly compiler message. So yeah actually, there's a movement now, in the F# community, to make the compiler messages more friendly. And we have Elm as the goal.
JORDAN: And I think that, it's not like when you dive into one of these languages, like either Haskell, Elm, PureScript, OCaml, Reason, it's not like, you've gone in this one direction and, "Oh no, I've kind of strayed from these other languages, it's going to take a lot of work to learn the other ones." That's not the case, it's actually, once you learn one of these ML-derivatives, they all kind of come from the same family of programming languages. Once you learn one, learning the next one is just really easy because you can relate a concept of one to the other instantly.
KENT: I think that's actually been one of my fears, so I'm glad that you mentioned that Jordan. To be perfectly honest, I totally love the idea of a typed system, the idea of functional programming, but I've yet to actually jump into it because there's a little bit of decision like fomo going on there, which one should I really pick? And also it's a matter of, how do I find the time to learn this stuff? Like when I'm not doing it on the job, I can't convince my boss to let me build something new in a language I've never used before, so like finding the time to do that. But yeah, I'm really glad that you mentioned, you just kind of learn one of these-- and you mentioned ML-based languages, if you could actually define that for us, that would be really helpful.
KENT: (laughs) That's right, yeah.
JORDAN: Yeah so you can look up on Wikipedia the history of ML and OCaml and Haskell, and you can see that these things have been-- these language have been around for decades, really. And these ideas and the implementation of the types, it seems like it's been around for a really long time. And they're all kind of taking inspiration from each other and the history is more complicated than a lot of people kind of describe, but to reduce it down to a simple story; you have this ML family of languages from which Haskell and OCaml and then eventually, Elm and PureScript have derived from. Phil might be a better person to speak to that.
PHIL: I think that one thing that's sort of quite important about ML is the fact that we have type difference for all our terms, right. Some people are about perception and types of languages in general just because they're used to types that seems worthy to write the most types on all of the indiscretions. But one of the benefits of sort of ML, and the ML family of languages, is, you know, we don't have to do that. The compiler-- we sort of just make sure our programs are correct, but the compiler will do that without having to write up a type of exceptions. Really, really powerful programming.
DAN: Sorry, is that mechanism synchronous?
KENT: Oh no, Jordan fell out again. (laughs)
KENT: That's awesome! Do you want to talk about PureScript, Phil?
KENT: Yeah, that's great.
RICHARD: One more note to mention, based on what Alfonso said, so you noted that Elm has its own package manager, which is true. And it's not just because Elm wants to just like be cool and hip and doing something other than npm. So you can npm install Elm, the compiler itself, just npm install-gElm and then you're good. But what he was referring to is that Elm's library user system does have its own package manager and the reason for that is that it actually puts guarantees on those packages, specifically about semantic versioning. So if I write a package and I release it as version 1.0, and then I make some breaking change, like I change the way some function looks or I delete the function or something like that, and I try to publish that as a minor or patch version release, the package manager will actually reject that. It'll say, "No, you made a breaking change. You have to increment the major version number." So the results of that is that semantic versioning is actually guaranteed across all packages in the ecosystem. Which is pretty cool because it also means that when you do constraint solving-- so like in npm when you install a module, you get all of the dependencies that come with it. And so that can result in sort of an explosion of lots and lots of different things.
So Elm does it differently where instead, it says, okay when you say I depend on this version range, it will actually just download one copy of each library and then it will just find versions that fit with all of your different libraries. So you actually get a really small footprint, even when you have lots of dependencies because even if they're using the same module, it'll just find versions that they can all talk to one another with. So you get a much smaller sort of footprint. But yeah, basically the reason it's able to do that reliably is because semantic versioning is respected and if it were not respected, and it were not guaranteed, then it would be pretty easy to have that constraints over result in things that were actually incompatible even though they claimed that they would be compatible. So there is a good reason for it having its own package manager.
KENT: Yeah that sounds pretty awesome.
KENT: I'm glad that Dan asked that question earlier about iteropt with like current applications because I think that's like a must-have for any of these languages. Just like you said earlier, Richard, anybody that thinks they can rewrite in a new language is wrong. (laughs) So cool, we are coming down on our time, but if there's anyone else has something they want to just mention before we go, with other questions, now is the time. Jordan you can go if you'd like.
KENT: Sweet, so many things to look at. Hopefully we'll get all these things in the show notes so people can check them out. Great, so let's go ahead and-- I don't think we'll have time to get into all of the Twitter questions, but let's try to do this as quickly as possible, so we can at least mention resources or something for these people who are asking and interested. So, let's see. Eric Rasmastan asks, "If starting from scratch like untyped JS, should I go with TypeScript or Flow or something else?"
RICHARD: You should go with Elm! (laughs)
KENT: What would be a good thing for someone who hasn't really jumped into typed languages or functional programming, if they wanted to add something to an existing application, where would be a good place to start? They should just go all typed functional or should they just start adding a couple types here and there?
RICHARD: I mean my personal advice would be-- obviously I'm going to say you should use Elm but (laughs) I would think of it less as trying to gradually convert your program to typed, as much as picking some part of your program and saying, "How can I make this one part of my program, as nice as possible?? And so that's sort of what's worked well for us, is just saying, let's make this one thing-- even in a different language or even just saying, let's make this one part typed, what have you. But as I said earlier, I think there's kind of a spectrum and typing is only one part of it. I mean the typed functional is, for me, more important than the typed. There are a lot of people who, for example, if you asked me would I rather use ClojureScript or TypeScript. That's not-- I obviously like typed checking, but I can easily see myself answering ClojureScript because ClojureScript is awesome with the mutability, the concurrency, all sorts of different things that TypeScript wouldn't get me. So I don't know if the typed part of the typed functional is necessarily the end all be all even as much as do like it in the context of Elm. So, my two cents.
BRIAN: Yeah, I'm going to throw in there that when you're doing functional programming, it all comes down composition. You're not setting state to tie things together, you're just passing one value to the next function typically. So the types really shine there. So if you're using types in an object oriented setting, it might not shine as much as it would in a functional setting, so they do go together quite a bit.
ALFONSO: Yeah, I think Jordan's right. This is something we don't talk that much to be honest, but what's he doing in the language is very important because you have to-- you can exercise this discipline, but if it's not going to matter as soon as you work with a team or working with other people. It's very difficult to keep (mumbles). And also, the key word is discipline that you have to do everything by yourself. And then the compiler is not helping you on that. Compiler like Elm, PureScript, Reason, F#, it's helping you. It's much more difficult that you're making mistakes.
RICHARD: So more directly, I was actually specifically doing this, before switching to Elm, I was really doing basically like, pretend that we're writing Elm code, like don't ever mutate anything, always use constant whenever possible and things like, only use functions. And here's the thing, there's a very concrete case in which discipline is absolutely useless and it's when you're refactoring. When you have a big chunk of code and you've been really disciplined about writing it, and now you need to change it, if you have a compiler that will say, you know-- we've done this several times, where we'll take some big chunk of Elm code, do a big refactor, clean up stuff, make the API nicer and then afterwards, the compiler is like, "you missed this thing, you missed this thing, you missed this thing and then you forgot this piece of code that you haven't touched in six months." Discipline totally does not help you there. Tests can help you there, but the problem with tests is that if you're doing a big refactor, that usually the first thing that happens when you do a gigantic refactor is that you break all of your tests and they don't apply anymore, they're now covering code that doesn't exist anymore. And I have never, in my entire programming career, found a way to have a as nice refactoring experience as I now do in Elm. No matter how many tests I write, no matter how much discipline I use, there is just absolutely no way to get that experience without compiling.
KENT: That's actually really a great point, thanks for bringing that up. So we pretty much don't have anymore time for another Twitter question, but this one just came in and I'm really interested in the answer, so I'm gonna ask it anyway. It's by Ville M. Vainio, and his question is, "Any complaints about debugging/source maps?"
PHIL: Yeah, we have source maps in PureScript as well actually and again, like what you're saying Jordan, if the translation is simple enough, then often you don't find any of them. Often I've used the source map feature in PureScript when I'm using PureScript Alpha, but I think that's more because of, you know, in functional languages we have other tools for debugging. So I tend to just sort of use the repl, much more than I would use the Chrome debugger or something. But if I really sort of need to dig in and go line by line, I'll use the Chrome debugger. That works fine, but in a pure functional language, you have the benefit of using a repl and testing to get small ideas of making sure these things all work. If the small things work, it compiles into large things. So yes, we can have a nice debugging tools but we can also re-enable these nice other debugging tools that you can have in other languages as well.
JORDAN: And also the joke is that if you're using a ML-derivative language like this, then if it compiles, it works and you should never need to debug.
RICHARD: Yeah, it's funny because when I used to do CoffeeScript all the time, I really liked source maps because it meant that when my code drew run time exceptions then I could see where the culprit was. But now, I just don't get run time exceptions. So it doesn't really come up as much. But yeah, Elm obviously has a lot of-- like a long history of awesome debugging tools. So like the Time Traveling Debugger and stuff like that, that are not necessarily integrated with the browser, so much as they are separate stand-alone tools. But currently, the Elm reaction that likes Time Traveling Debugger is not as awesome as it once was, but the next release is looking to make it as awesome as it once was before and I'm so unbelievably excited about what that debugging experience is going to like, I can't wait. (laughs)
KENT: Cool, well thank you so much everybody for answering. I'm afraid that we are running out of time, so we need to get into our tips and picks and closing up the show. This has been super awesome. So thank you, thank you, thank you. Let's go ahead and we'll get into our tips and picks. Dan, I think you need to head out, so why don't you go first?
DAN: Yeah, so I only have one pick, which is just a shameless plug. So I was working for the past several weeks on Create React app. This is a tool that lets you get started with React environment, where it quickly downloads like Backpack and Babel and ESLint and all this stuff that people usually use in production projects, but it's still very developer friendly because it doesn't have any config. So there's like literally zero configuration. You just run a command, npm start, and you're up front. So check it out, it's from React blog. It's the last entry in the blog, Create React Apps with No Configuration and let us know what you think.
KENT: Awesome, cool. Brian, do you want to do next? He says no, Pam?
PAM: Sure, I've got one ready. Well one, Create React, that is definitely awesome so good work, Dan. So I am actually also picking-- this is actually a minimal closure script template. So mi-es or mies? But in case-- you heard from all these great language creators and you said, "But what about ClojureScript?" You can go try to ClojureScript template. It's nice because it solves that problem of giving you somewhere to start and to try it out and mess with it.
KENT: Awesome. Jordan, why don't we have you do next?
JORDAN: Alright, a couple of things. Check out the book, Real World Ocaml. It's free online and you can order a hard copy of it as well. I didn't write the book or anything, I'm just am huge fan of it. It teaches languages and the statically typed, functional languages that we're talking about here. So check that out. It's free. The other thing is, if you're using Atom, I really recommend that you use the Vim-Mode-Plus program plug-in. It's really good. It should be the default really. It should be the official one and the developer's super responsive and he responds to bug reports really quickly, fixes them and takes user feedback. So yeah, check that out.
KENT: Awesome. Phil, why don't we have you go next?
PHIL: Yep sure. So I've a couple of picks. The first one, I just wanted to point to the PureScript website, it's purescript.org. So if anyone's interested, it has all the links to all the resources. So thing's like module documentation and language guides, the link to the book, all these sort of things. And the second one, I just wanted to sort of highlight a library from the ecosystem. So the one I chose is called PureScript Pux, which is a UI library. It's really nice, it's sort of an implementation of-- I guess it's sort of a combination, takes inspiration from Redux but also the Elm architecture from Elm. It's really nice. It has a lot of the tools that were mentioned before, like the Time Traveling Debugger, these sort of things. But yeah, that's all I was checking out.
KENT: Great! And Richard.
KENT: Great, great. Alright so that's our show, thank you very much everybody for coming. Let me just give a couple closing announcements. So we do have Silver sponsors we're grateful for. ReactJS Program, it's a great master the react ecosystem site. And Sentry, is cross-platform crash-reporting, so check them out. And then if you have suggestions for the show, guests or topic ideas, go to jsair.io/suggest. That'll take you to a form. And then jsair.io/feedback, for you to submit feedback on this show or like the show in general or past shows. Really appreciate the feedback. Then jsair.io/email will take you to a place where you can see our previous newsletters and sign up for the newsletter. We do like highlights from the show and stuff. And then next week, again we're going to talk about how to be a mentor and so I recommend you watch that. It'll be great. And then yeah, that's pretty much it. So thanks everybody, really appreciate you coming on the show and we'll see you all later.