My feelings about static vs dynamic typing
Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.
Can't we all just get along?
Eric Normand: Why is the static versus dynamic typing debate so painful?
Hello, my name is Eric Normand and this is my podcast. Welcome. Today we're going to talk about the static versus dynamic typing discussion, debate, argument, fight. I want to talk about it from a personal perspective. I don't have much to add to the debate. I've participated in it. I read a lot. Besides what I've already added. I do want to share a personal, personal side to it.
I'm troubled by the debate. I'm troubled by the way we are going about it. I think there's a lot of value in this discussion, the tension between static typing and dynamic typing. A ton of value.
They're obviously distinct and obviously have successes on both sides and benefits and disadvantages on both sides. What troubles me is the level of discussion that we're having.
I want to keep it personal and not just go into abstract problems I see. Personally, I've written some articles taking a position on some aspects of the debate. It's a big debate. It's been going on for years. It's not going to end anytime soon. That's for sure.
I feel unheard by both sides. I have an article out there where I was trying to comment on some of the points made in a Rich Hickey talk. I'll find the name of the article, hang on. It's called "Clojure versus the Static Typing World."
Rich Hickey gave a talk and he made some comments in it. I wanted to share my personal experience. I worked in both Haskell and Clojure. I had what I thought was a perspective that hadn't been heard very much. I've talked to several people who have started using Haskell and they love it and will never go back to a static language.
I did. I learned Haskell a little bit in school, but I mostly spent my time with Clojure after it came out. Then I got a job at Haskell. I did it, I liked it. It was interesting and I gave it maybe 75 percent of my heart. I did not join Haskell communities online. I didn't go deep into it, but I learned enough for me to function at my job.
I learned to appreciate quite a lot about Haskell. Then I still missed Clojure and I felt good going back to Clojure and it stands on dynamic typing. Anyway, I felt like I had a good perspective, different perspective from what most people have because most people who go to Haskell don't go back.
I've told people that I've gone back and they are surprised like, "I've never heard of someone who's done that." I did. I wanted to give my personal interpretation of the kind of stuff that Rich Hickey was talking about.
I was mostly groping and fumbling around trying to put my finger on why some of the disadvantages that I saw that Clojure was better at than Haskell. Some of the things that Clojure could do better than Haskell. Not saying it's a great essay or anything, but I got a lot of responses. They were civil, I guess, but they weren't very Caritas.
They didn't give me the benefit of the doubt, somehow. One of the things I said was that one of the nice things about Clojure is, you can read a data structure like a JSON. That you don't quite know what the structure is, and you might know some things, but not everything. You know, it's JSON, but you're not sure all the keys, some of the keys.
Then also, sometimes you read in a thing, and the strings have parse errors in them. They're strings, but they're supposed to be interpreted as, say, a date. Then it doesn't parse as a date, because they typed it in wrong. It breaks your expectations. What do you do with that, and you have to deal with that.
Sometimes you don't have to deal with it, because you didn't even care about the date. There's all these. There's a very complex thing going on here, that you've got choices. In the Clojure world, the idea is get it into the system, deal with that later if you need to. Deal with the problems of the parsing and everything, because you might never need it.
Don't try to impose a structure before it's in the system. In Haskell, it's much harder to...It's not that it's impossible, but that the attitude in the libraries in the community, the kind of the practices of the community are to define a type that this JSON will be converted into.
If you don't do that, and you leave it as JSON, it's hard to work with. It's hard to work with raw JSON within Haskell because you have all these cases where well, what if you think it's a string, but it's really a number, and now you have an error. Whereas in Clojure, the types are much looser, and you can do stuff with them.
You can print them out and check what the types are and stuff without actually knowing. It's more convenient. There's lots of stuff in Haskell that's more convenient, too. Don't get me wrong. This is one of the things that Clojure has made easier than Haskell.
This was the argument I was trying to make. Some people took that to mean that I don't understand how types work or how total functions work, how it can't make sense to allow map over every type, which it appears that Clojure does. I don't believe that map is a total function, is just that Clojure does not help you learn that at static compile time.
Clojure does not help you learn that you passed in the wrong type of argument, but still we think about types. We know that map only really applies to sequences, it doesn't apply to say, a number.
It's not that [laughs] someone disagreed with me. It's that I felt I had a lot of Clojure is shouting on my side, saying, "Yeah, yeah, that's right. That's right." I don't know if they understood what I was trying to say.
I had a lot of Haskellers shouting, "No, no, you don't get it. You're wrong, and you think this, and you think that." I didn't think those things. My article was not about those things. I just felt unheard, unlistened to. I don't take it personally anymore, I used to. I've been writing online for a long time.
At this point, it doesn't faze me, like it used to. I've come to expect it that people are going to read into what you say, a lot more than what you say. What bugs me is that it's so systematic. I don't believe we're ever going to be able to hear each other. I say systematic, I mean systemic. That we're now so divided that if I make a comment as I'm labeled as a dynamic typing person.
I make a comment about a static type thing. I'm placed with that label with a matrix of other beliefs and assumptions and mistakes that I'm not making. I cannot speak and be heard. People just want to win the fight or define their stance. I saw this happening quite a bit.
Rich Hickey gave another talk. Where he talked about the problems with one single type, even the type was in the name of the talk. The type was maybe, and he was talking about how it didn't solve the problem that he saw needed solving.
Yet people would recommend he used that for his problem. He was describing the problem with using maybe for that problem. People just could not hear it. I had people comment to me that they've got very angry. These were static typing fans. I'm a fan of static typing. They were very angry. They got angry at a conference talk.
I'm not saying that Rich Hickey was right. I have re-listened to try to find like, "What did he say? What specifically was so wrong?" I couldn't find anything that was wrong. I went looking in other people's responses to it. They're not responding to what he actually said.
It happens on both sides of the debate. If someone says something good about static typing. The dynamic typing fans will...If someone says something good about static typing or something bad about dynamic typing, the dynamic typing fans get defensive as well. Their blood boils and their adrenaline gets ready for a fight. They stopped being able to evaluate the statement being made. It saddens me.
I'm sad. I'm sad that as an industry, we can't get over this. We need to be able to talk. If Rich Hickey was wrong about this, that's fine. I didn't see it as a takedown of static typing. Let me put that another way. I did feel a little bit of "Yeah. That's what I felt when I was using Haskell, yeah."
Later, I was a little ashamed of that. I was ashamed that I would feel such a strong sympathy and excitement that we were digging one in. Rhetorically, we're all guilty. We're all guilty. We all make claims that we don't have any scientific evidence. We only have our personal experiences.
There's not much evidence that there's a difference between static and dynamic typing in terms of reducing bugs or going faster or whatever claims people make. As an example, it has been shown that getting a good night's sleep is more significant. Then we're like the choice of language.
If that's the thing, [laughs] we should be debating how much sleep we need to get. Not what language or language features we need. I'm ashamed of myself for having participated in the past, in the debate, in an unfair way. I wonder if there isn't some kind of healing we can do.
From my perspective, both sides have advantages, they both have disadvantages. If we don't listen to each other, we'll never make a best of both worlds scenario.
It'd be awesome to have the benefits of a dynamic, system that can deal with the unknown parts of your data, the unknown world, changing world, and have the awesome properties and abilities of a language with really strong static typing.
I don't see why we can't have both. I know that there's people working on optional and gradual typing. I don't know if the answer is there.
I'm glad that's being worked on. Sometimes I feel like that's being worked on by people who are more static type orientated and so they're missing something. That's fine. Everyone should work on that. Everyone should be involved in that.
They are probably the best able to work on that because type systems are really hard. [laughs] They are hard to get right. You need a lot of math and what have you, and so people who gravitate towards that mathy, formal, logic, they are the ones who are probably better equipped to get it right.
I don't know where to go from here. I'm not like a person who can bridge these two camps. There's de facto camps but there's no official camps. It bothers me. I wish there was something I could do. I'm sad about it. I get upset when I don't feel listened to or heard. What do you do when someone hears so much more than what you said and they start arguing points you didn't make?
What do you do? I do want to talk about a couple of points. I want to be balanced in this, try to give a point from both sides, because I don't want this to be taken as partisan in any way, but the rhetoric that we're using. When you hear someone use rhetoric, and you're not part of that community, and you hear someone affirm it, it's obviously the truth. It's scary.
Other people outside of that community don't believe it. It's almost very cult-like. You're all saying the same phrase in this community that's meaningful to you. When someone's outside, that's a meaningless statement.
One of the things I hear in the static typing community is something like static typing eliminates a certain class of errors. It's that very phrase as if that's verbatim. I hear that a lot. It's a meaningless statement. I don't want to logic chop it too much. Let's do it a little bit.
Before we do that, let's talk about what they mean. If you give them the benefit of the doubt, which is important, we need to practice this. They probably mean that there is a certain class of errors that some dynamic languages have, where you pass the wrong type to a function.
There's no static typing, you can't know that it was the wrong type, until runtime, and it has a bug. Program crashes or throws an exception that's caught somewhere else and your program does the wrong thing.
That's probably what they mean. It's hard to dig in and understand it but if you're generous, you can hear that and what they're saying. There's a certain class of errors. I passed a string when I wanted a number. I tried to add it, or I tried to divide by a string, and boom, it crashed.
That's not possible in Haskell, because you can't pass a string to a function that's going to do a division with that. It's just going to tell you no.
You've eliminated this class of errors. You've basically moved them to compile time so that they never enter production. That's good. That's a good thing. Eliminating these errors, that's great.
The rhetoric is what I don't like because certain class of errors is actually meaningless. It's empty of content. First of all, you can have an empty class. Anything could eliminate a class of errors if it's an empty class. That's maybe a little too logic chopping.
But a certain class? Could you at least name the class and not just say, a certain class? Everything eliminates a certain class of errors. Having a null pointer exception eliminates a certain class of errors. It eliminates crashing your program and doing a core dump.
Like, "Oh, we can't pass a message to null so we're just going to throw an exception instead of trying to pass it to null and dying." The referencing, no. You could just say anything eliminates a certain class of errors. It's doesn't contain any information.
You got to, and I've seen it in conference talks, people will stand up and say, "Well, I believe in Haskell because it eliminates a certain class of errors." You're like, but that's [laughs] everything communicates certain Clojure. Not writing a program eliminates a giant class of errors.
Dynamically checking your types also eliminates a certain class of errors. What class? The class of errors that you remember to check [laughs] and manage to check correctly. It's a meaningless statement.
It would be nice if that was named, and if it was named, it probably wouldn't be something you need to repeat, because it'd be obvious. Haskell eliminates runtime type errors. That's it. Yes, that's true.
You have to use type error type as the way Haskell defines it. Not in a more dynamic way. In a way like stringly typed language would define it, where a string with numbers in it. It can be interpreted as a number, a string with digits in it, it could be an integer.
The type error in that kind of language will be if you have a letter in your number, or in your string. That couldn't be interpreted as a number.
Does static typing eliminate that? Not quite, because if you parse something... I'm just trying to say that there are different definitions of type and different notions of type that has to be taken into account. It's a complex thing.
You can define type in a very formal and strict way, such that, it is type checkable. You can write a practical type check for it that doesn't explode when you give it a real program. That's what Haskell has done. It's a real feat of engineering to do that and to design.
I want to give an example of the rhetoric that I hear on the other side. On the dynamic typing side. Which is something like "Static typing prevents me from expressing the constructs that I want to express."
I don't know if I have a real verbatim thing that I hear all the time. Maybe some people say, "Static typing makes me go slower because I have to think about the types, and not just about what it does." There's some truth to that. You do go slower, just because there are two things to think about. The types and the values.
In the long run, it's probably better to have a computer be doing the logic consistency checking for you. It's what the type checker is doing. Then it can be correct. If you get the type system on your side, it's really helpful. It finds things that you hadn't thought of.
From my experience working at Haskell, eventually, you realize how, unsafe isn't the right word, but how unwise it is to return different types to return the same function, or to make something ridiculously polymorphic for no good reason. Like, "Oh, this takes a number or a collection of numbers, and if it's a collection of numbers, it does this one thing. But if it's a single number it..."
Why? Why make it polymorphic like that, so that it works with a Singleton argument or a set of arguments. It doesn't improve even the usability like you think. That's something that the dynamic typing world can learn a lot from.
The reason the type checker works so well, and it can identify the types of all the things, is because the types have to be simpler and more consistent. Simpler and more consistent, that just sounds good. It forces you to be simpler and more consistent? "Yeah, hello, that's awesome. Give me more of that, please?"
That idea that type checker makes you go slower, it's true when you're learning. You make a lot of mistakes, but eventually, it gets on your side. You get it on your side, you change internally to understand it better, and you can start using it.
At that point, it makes you go faster for the things that it's good at. It's not going to be fast at the things it's bad at, but for normal everyday programming, it really helps.
I did want to give those two examples. One from each side. Just showing that how sometimes the statements we make on one side, doesn't make sense from the outside. They're almost cult-like. Can you really say that it makes you go slower? Have you learned that somehow? Have you given it a really good test?
If you're learning the type system and trying to test your speed at the same time, that's not really fair. That's not a fair test. It's like saying, "English is my first language, and I speak some Spanish. If you ask me to say something fast in Spanish, compared to English."
I'm just going to say, "No, Spanish just slows me down. If I got better at it, maybe there's things in Spanish I could say much faster than in English." That's an extreme example, but I'll probably never be as fast in Spanish as I am in English. [laughs] Just because it's my native language. It's a fine example. It's OK.
This has been on my mind for a while. I was dreading it because I was even worried that I'd get super emotional about it. I just wish that we could get along, we could learn from each other, talk to each other, listen to each other, and work together. Make something better than what we have on either side.
My name is Eric Normand. This has been another episode of my podcast. Thank you so much for being there, and as always. Rock on.