Transcript
Speaker: So welcome to DeafN, I think the final episode of this year. And amazingly enough, we have a repeat guest on this episode, episode number 56, all the way from episode number 27. Eric, welcome back. Hello. I'm happy to be back. This is awesome. You're the first repeat guest. How does it feel? You know, this is like an achievement or achievement unlocked.
Speaker: Maybe like a broken record, I guess? No. No, it's really cool. I listen to the podcast, so it's cool to come back on. I mean, I meant achievement for a different podcast itself because we never thought we were going to be long enough to have somebody come back. It's not an achievement for you. It's just for us. We'd have you on every week.
Speaker: Yeah, thank you for having me on because I know there's a lot of great people to talk to. You didn't have to repeat. You're finding cool guests all the time. Yeah, but you're still cool, so that's good. And also, you've been doing a lot of stuff, so it's nice to catch up. Yeah, although you and I, Ray, we talk. We talk now and again. We talk now and again, yeah.
Speaker: Yes. So how is it going, by the way? I mean, I never pay attention to anything other than DeafN. Obviously, DeafN is there. It takes up all your time. We know. Exactly. We have practically 19 hours a day. Come on. VJ is actually going to another language podcast. You're doing a Rust language podcast. We had one episode. You've had two, haven't you?
Speaker: Yeah, too. I know more about his podcast than he does. You're learning Rust, Vijay?
Speaker: Yeah, I'm trying to. It's another one of those things. I'm trying to get to the non -GC languages from the history. I tried Visual C++, C++ a long time ago. CC++, that's how I started. So I forgot how cozy it is with the GC stuff. So I'm like, oh, let's try this shit. And then it's a different world completely. It's fun. It's kind of a functional but non -GC stuff.
Speaker: Yeah, so he has a Rust podcast, which like you say, it's done two episodes, maybe he'll do more next year. But uh, but yeah, me and Eric, we do something proper, you know, we do
Speaker: It has a prop in it. Well, actually, I mean, the nice thing about Apropos, which is the YouTube channel, is that we've been doing that, I don't know, actually, is that about a year now? Yeah, a little over a year. And that's really nice, you know, I think it's, we never have any guests on there. So we can
Speaker: please ourselves. I think we had a guest one time. Oh yeah, we had Stuart Holloway. We have Royalty on. They're not really guests, are they? That's a nice way to insult our guests. But luckily. Exactly. So Eric should know.
Speaker: So what have we been up to, I reckon, in the last two years, whatnot, eight months, nine months? Where do I begin? Well, the big thing I'm working on is my book. I started that maybe a year and a half ago. We're all rounded up to a year and a half. Yeah, it's a lot of work. And it's taking way longer than I thought.
Speaker: But it's coming along and it's going to be a really great book. It's all about functional programming and it's not enclosure. Everyone asks me that because I'm like a closure. Why do you hit closure, Eric? Can we ask you the first question on the Deaf Enclosure Podcast? Why do you hit closure? Come on.
Speaker: Where do I begin? Yeah, I know. I have a blog post ready. I mean, almost published about all the things that are wrong with closure. Bring the holiday cheer, yes. No, I mean, specifically, I think that the ideas, I mean, let's put it shortly. My goal for the book is to make functional programming accessible to a wide audience.
Speaker: And starting with closure and having to teach closure to people, you know, it's just not what it's not it wouldn't fulfill the goal. Plus, it would be kind of preaching to the choir like we already believe in immutable data and stuff like that. So there's no, you know, it would just be kind of
Speaker: I don't know, master, but don't worry. So just let's just talk about all the mental masturbation you mean? Yeah, like an intellectual. Yeah, yeah. Yeah. That's an interesting starting point, though, isn't it? Because if you're not gonna, I mean, obviously, what I'm interested in is like the precepts of functional programming.
Speaker: Listen to your podcast as well because I think that's a really interesting one because you talk about functional programming on your podcast, but you talk about Haskell and Clojure and JavaScript and all these various things, but you identify yourself in that podcast.
Speaker: as a closure programmer. So, but why is that something you do in the book, you identify yourself as a closure programmer, and that's your influence? Or is it like, is it like a hidden hand of functional programming? That's the big reveal.
Speaker: By the way, you just learned to close your throat. Exactly. Just put a few parentheses at the beginning. The parentheses are here and they're all still in the middle.
Speaker: Yeah, that's a really good question. I don't think I'd talk that much about closure in the book, except where it's like, oh, you know, this is how closure does it. This is how, you know, you're learning the real thing. You know, this is how other languages do it.
Speaker: including Haskell, but I don't ever say like, I'm a Clojure programmer and I'm teaching this stuff. I do think that Clojure gives a very useful perspective to functional programming. Let me just contrast it with another, I think, very well -designed language, Haskell.
Speaker: it focuses much more on the types. It's sort of like, let's get this language out of the way, have immutable data and pure functions and first -class functions. And now let's get to the types because that's where the interesting stuff is. And as closure programmers, I don't think we believe that so much. And so a lot of...
Speaker: A lot of what the book is doing is taking those closure approaches to functional programming and bringing them to a wider audience. I was going to say that just to give a little bit more context in the book about the book, I need to give code examples. I use JavaScript for that just to make it have as wide an appeal as possible.
Speaker: So you don't have to learn the language before you start doing the functional programming stuff. I chose JavaScript because, I mean, it is a very popular language, but it's also readable by people who know Java or C or, you know, you can, you can, and I mean, it's readable. Like it says function, you know, when you create a function, you don't have to use the ES7 syntax. I don't use any of the new stuff. It's all the old school. It's the OG JavaScript.
Speaker: I mean, I've had people in comments say like, oh, you should use some of those new features and use let instead of const. And I'm like, I don't want to get into a discussion about let versus const. That's not the point of the book. I'm just using var everywhere. I know that some people are going to be like, oh, but you got to teach new. It's not teaching JavaScript. That's not what I'm doing.
Speaker: I don't want a Java programmer to come in and be like, what is the difference between let and const? Sometimes you use let, sometimes you use const. I don't want that to be on their mind.
Speaker: But it is, if you see like teaching functional programming, what I felt is like these days, every type of programming methodology that you want to learn is attached to a language, right? It's very difficult to abstract it away and then explain, only I'm going to explain functional programming to you. And then you can implement that in any language you like. Some languages are more flexible to implement this. Some languages look horrible when you implement this.
Speaker: So I don't think it's an easy, I don't know the English word, like the teaching method called functional programming is tricky, but I understand your approach because you're not going to take, you're not teaching JavaScript. I think you said it, you know, very, very nay, in a very nice way that you're not teaching JavaScript, you're just teaching functional programming fundamentals. Right. And this is how you can write in version one of JavaScript and then whatever. And then later you can pick it up. Exactly.
Speaker: Yeah, I mean, what you said is really true. It is hard. And that was one of my complaints. And one of the reasons I started the book is because so many books about functional programming are either super academic, and they don't really start with the basics. You kind of have to be, I don't know, have a PhD advisor guide you into it.
Speaker: or they're just about a particular language and one language's approach to functional programming. But completely, I feel like doing a disservice to the beginner who just would benefit from just identifying pure functions. That is a huge thing and I think it's the
Speaker: It's the start and everyone like has a little footnote somewhere like one sentence like okay and these should be pure functions like what no that's. That's it like that's the meat of it that that's where you should start liking.
Speaker: Talk about pure functions, why they're better, how do you identify the impure functions, and how do you refactor it so that you have less code in your impure function, more code in your pure functions. And so my book spends the whole first seven chapters just on this idea.
Speaker: One thing that I find, I've said this many times, but I will say it again to you, and I'm interested in what your take on it is, is that I think as a branding exercise, functional programming has got an absolute huge problem because functional is a completely stupid name for a programming style. Object orientation, there's something behind that.
Speaker: you know, sort of imperative, there's something behind that. Functional is just so overloaded these days. And I also don't think it properly describes what FP really is. So I think what's your kind of manner that you your book title doesn't use functional programming uses you talk about simplicity. So what how do you feel about like the branding issues around functional programming?
Speaker: Right. So I'll say the book just for the audience. Grokking Simplicity is the name of the book. But that's a really good question. I didn't give you the questions beforehand, so sorry about that. No, no, no. But it's a really, it's a good question. And it's a problem that in one of my drafts, I like tackled it head on like, why am I,
Speaker: I kind of redefine everything, like give it everything new term because I feel like the terms are very confusing. Functional programming, it makes you think that it has something to do with functions. And a lot of the definitions, including the one on Wikipedia,
Speaker: make it all about functions. And they'll say it's programming with mathematical functions, otherwise known as pure functions. And I think that that just does such a disservice to what we do day to day. I mean, for instance, as closure programmers, we use side effects, we use a state, mutable state.
Speaker: But we're still doing functional programming and I feel like we have a lot to say about state inside of it. I'm kind of like going a bit higher level in that because I think the notion of something that is functional means that it's something that works in the English language.
Speaker: It's overloaded in that sense that of course, programs should be functional. It feels like it's kind of like a philosophical debate rather than a kind of pragmatic debate. That's why I mean. Haven't we already moved multiple levels from that by introducing things calling variables which are not actually actually variables?
Speaker: But we already overloaded them. We used so many mathematical terms in totally different ways. They are variables. Why are they not variables? Well, a variable in math doesn't change. Mathematics is wrong there. No, a variable in math doesn't change. It varies.
Speaker: If it's variable, then it must be subject to change. So, okay, this is a common confusion, especially among programmers. Like when you have a variable in a formula or something, a mathematical formula,
Speaker: It varies with each use of that formula. So in this time, we'll say x equals 1. Well, let's try it with x equals 10. But within the run, it doesn't change. And as we think of a variable as programmers, we think of a place to store a value that will take different values throughout the course of it. And so then we think, but how is it a constant variable?
Speaker: The original variables were constant for that run. But it's not the thing, no, it's not one of these, it's like where we are fighting these languages, you know, like you said.
Speaker: And then function, it's like, well, it's a function. It says function in JavaScript, that type function. So that's why I throw away all the terms. So I don't use, I mean, I explain the terms, but they're not what I use in the book. I use actions, calculations, and data. So distinguishing these three things is like what I consider the gateway, the first paradigm shift
Speaker: It requires being able to distinguish these things. I get data. Data is definitely different from actions and calculations. On first blush, I've listened to your podcast, I do know the difference. But when I first hear those two things, actions and calculations, I'm not exactly sure what the difference is. Maybe that could be worth going over.
Speaker: Isn't calculating an action?
Speaker: In this context, because it's closure people, I feel like we can go kind of deep on this. It's true. Calculations are actions. They're subsets. The set of calculations is a subset of actions. And data is a subset of calculations. Because we know that if you wanted to make a Turing machine, it would be actions.
Speaker: It'd be like moving the head, the read head, reading a mutable value from underneath wherever you are. So it's all actions. But you can simulate calculations using that Turing complete system. And then we know by lambda calculus that you can represent data using functions.
Speaker: using mathematical functions. So they are subsets. The thing is, you don't want to be working on that subset hierarchy all the time. You want to get the benefits of the calculations and the benefits of the data. So you just kind of stick. You use the compilers, features to stick within that domain, the calculations, the data, the actions.
Speaker: Does that explain it? I understand it. What you're doing now is you're saying that actions are side -affecting. That's a difference between calculations and actions in your vocabulary.
Speaker: Yeah, actions, actions are what you might call an impure function. Except function, the problem is function like sounds like a feature of a language, right? Like a JavaScript function. Because a lot of actions are not functions. The action might be an assignment statement.
Speaker: Right? Or the action might be, you know, it could be a method, which is kind of like a function, but it could be an operator. It could be the plus plus operator. So it's really, I'm trying to just like totally use new terms that are outside that don't have features attached to them. Yeah. So you're using JavaScript to explain this concept in the book. Yeah. Why JavaScript?
Speaker: because it is very positive. I think it goes back to the beginning question, like, why do you hate closure? I'm tired of all the parentheses. That's what it is. The parentheses' keys broke off of my keyboard, and now I'm just tired of it. Sorry. So why does that look good? Too many.
Speaker: Why JavaScript? I like semicolons. You don't need them, JavaScript. But you don't need them, but you can use them. I love the fact that JavaScript people get really upset. Some people really don't like semicolons either. I think it's like spicing up your pizza.
Speaker: they used in semicolons, because if you are, then you'll get a bunch of hate from people who like, you don't need them. And if you don't use them, then it'll be even worse. So what's your, well, I think you can, you can have two versions of the book, one with semicolons, one with the other one, so you can buy whatever you like, you know, and on that you can sell to both markets. Yeah, exactly. No, inclusivity. That's what's important.
Speaker: Well, I do insert unnecessary parentheses in my JavaScript as well. I just surround every value in parentheses just to get a feel. I don't want to lose my closure.
Speaker: I need my rainbow parens to get some rainbows. Exactly. We all have funny languages. Why JavaScript? It's really popular. There's an automatic reach there.
Speaker: And then, like I said before, the syntax is readable. Even if they don't know the ins and outs of JavaScript, they can read an if statement, they can read a for loop. It's just something that they don't have to spend too much energy on.
Speaker: Of course, where it is something that they wouldn't know if they weren't a JavaScript programmer, I do explain it, but it's still readable. They can still read it, and if you name the functions in clear names, they'll get it. Who's the target audience? Because if you explain all these concepts, actions, calculations, and data,
Speaker: And then eventually you need to use these techniques in whatever the language that you pick up, right? Yeah. So how do you drive that home to the people who are reading the book? And what is your plan? So the publisher has pegged it at two to three years of experience, programmers for two to three years who already know a language.
Speaker: They've gotten into some weeds, made a mess, and they need some techniques to help them through. The way to make it stick, to make it practical to them, is I have a lot of exercises, step through refactorings of the code to make some JavaScript function more
Speaker: I want to say functional, but you know, just separate out like these are the side effects. These are the not like you don't need you don't really need to use a global variable here. You could use a local and so that's kind of in the weeds a bit Eric. I mean, it's at a high level. What is your kind of pitch round like?
Speaker: like functional programming what are you trying to sell to these developers when they've got there i've got themselves like few few years experience and why should they bother with functional programming is your answer you must answer that question as well.
Speaker: Yeah. So I'm attacking it from three vectors. I'm saying it helps you do reuse, testing, and maintenance, maintainability. So those are the like practical things I can sell about it. I think that there are
Speaker: There's also a group of people who want to do functional programming, but they can't find inroads into the current literature. There's a little bit of that too, but that's not something you can really sell.
Speaker: It's hard to find those people and target them. Really, I focus on those three. One of the reasons you're having a ton of bugs, it's hard to maintain, is you're just doing mutation everywhere. It's much more maintainable if you segregate that off into a little piece of code that you can spend extra time on, pay extra attention to,
Speaker: The other stuff is really testable. You just write test for it and you can leave it alone. This is going back to the closure stuff. It's like pulling things apart.
Speaker: We have a tendency to think that the bigger the thing is, the more it does, the more reusable it'll be. You think of some kitchen gadget that can do like 17 different things. You think, oh, it's so reusable. I can reuse it in 17 different ways.
Speaker: But really, the most reusable thing you have in your kitchen is the knife, the pan. Just the basics, the one -function tools are being used for almost everything. That's the approach I'm taking.
Speaker: make things more reusable by splitting them apart instead of having it do everything. At least you get to reuse a part because you might get part of it wrong. So if there's in two separate parts, you don't have to rewrite both.
Speaker: Yeah. So I think one of the long time ago, maybe two years ago or something, I read a blog post calling like programming has these three tribes. Like first tribe is programming as a mathematical thing, like applied mathematics. And then it's basically Haskell, even closure, lispy stuff into that one.
Speaker: And then the second one is programming is hacking the hardware to C, C++. I think that's the first time I read this mechanical sympathy. You need to know what the machine does or something. And then there is a... So C, C++ fall into that category, that tribe of programming. And the third tribe is, I just want to get shit done, so I'm going to hack something in Python and JavaScript and go home. It's like to make things work. So for me, I think those three seem to be valid.
Speaker: And do you agree with this kind of classification? And if so, then how do you see this functional things applying to three different areas? That is a really insightful triad there, and I'd love to read it. I'd pee, finally.
Speaker: I finally peaked by regurgitating some blog posts that I read like three years ago. I'm thinking about it though. You need all three, right? You need all three. Sure, you need to get stuff done, but that kind of development is going to make a mess. Maybe it's what he's doing. The first one is kind of got already. Second one might be difficult to reach because of the kind of performance issues or whatever.
Speaker: And it's more like the third one maybe is the interesting target for your book. I don't know. They get things done? Yeah.
Speaker: Yeah, because this is, I mean, I really start from in the book, I really start from, and thanks for all these like challenging questions, by the way. We improved from compost and PHP. Is it gradually kind of, you know, improved? All the crowd that we have been collecting finally being useful after two years.
Speaker: rich human. It's a rich loamy soil in which your weeds can grow and flower. Come on. What was the question?
Speaker: What was the question again? Yeah, it was about... The getting things done people. Yeah, the getting things done people, I think they'll make a mess, right? So my book, I mean, if that's the only attitude you have, I think that that's clear. Yeah.
Speaker: The book approaches like the first code you see is here's an existing system and here's how we would just like simply get the next thing done.
Speaker: It starts to say, okay, but this is what we would do to clean it up using functional principles. And it's just a lot of refactoring. And like, I don't know, I code that way. I code something like, what's the easiest thing to get this thing working? And then I come back later and I'm like, oh, this is a mess. I don't even know what's going on. I clean it up.
Speaker: I don't know the mechanical sympathy only comes in if i need to optimize it or something yeah yeah i feel i think it's a this is something that i've been thinking a lot lately thinking about all the course in enclosure and python i do a lot of python day to day.
Speaker: working with the data related stuff and i see when i pay with somebody who is doing python we just do something i know let's let's just take it straight through happy path if it works well done let's go home and then on the other hand when i'm trying to use color arrest for example rascal there that you have to think about.
Speaker: how this is going to fail and capture that thing. The result types or the option types or whatnot. That's a different thing. Closure seems to be falling in between somewhere. It's super productive because of all the REPL and these kinds of things.
Speaker: somehow because of immutability and all these things being available, I think my life becomes slightly easier. So I could see moving between these three. But as you said, I can totally agree. If I'm writing something in Python, I'm always waiting for when it is going to fail at some point. And then try to fix that bug. And so especially dealing with data, it's a pretty tricky situation to deal with that. There's another problem, essentially.
Speaker: I know, I know, I agree with the JavaScript choice in the sense that it has got broad reach and it's got a kind of interesting, what should we say? It's got an interesting functional nature, you know, because, you know, there is an argument that he was going to write it as a kind of version scheme. But then he was like, yeah, you've got to put this, you've got to put these, make it look like C because we want to attract Java developers, blah, blah, blah. Who knows what that, you know,
Speaker: I don't think that that story is fully told yet, but certainly the concept of FP was in there from the beginning, that's for sure. But my question is, and this is one of the things that when I'm trying to motivate ClosureScript people towards ClosureScript rather than JavaScript is that I talk about kind of defaults rather than possibilities, because with JavaScript, like most Turing -complete languages, like you said earlier on, you can do everything.
Speaker: But the question is, what is idiomatic? What does the language help you to do? What does it make straightforward and simple? And that's why functional programming languages are functional programming languages. That's why object -oriented programming languages are all languages. You can do everything you want to do in C, knock yourself out. You can be FP, you can be O, you can be
Speaker: clarity. If you can do everything you want, you can do logic there. So the question is, assuming you're going with JavaScript, do you ever allude to the fact that there are other languages that could make this more idiomatic, make it more supportive?
Speaker: By the way, after 20 chapters, this is the only chapter you need, you know, close your move on. Right. Right. It's sort of like in that book about Java concurrency, the joke that Rich Hickey read it and wrote closure so that he wouldn't have to do all the stuff in the book. Exactly.
Speaker: Because it's really true. You read it and you're like, oh my God, I have to do that. It's so hard. Okay, so it's a really good question. So I look at it like this. If you really want to learn functional programming, you need to do immersion. You need to get into a functional language and try to solve problems with the constraints it's putting on you.
Speaker: Because that's what functional languages do. They constrain you. They make you use immutable data. If it's typed language, they're making you use the type system. You're going to be forced to do it. And that is the best way to develop the thought patterns and the mindset that you need.
Speaker: However, as a pedagogical tool to teach the concepts, I actually think JavaScript is a good language for it. There might be better ones, I don't know, but JavaScript was good because, for instance, if I were to introduce immutability in Clojure,
Speaker: It would be like, okay, it's just a language feature. I don't need to know how it works. I'm just going to use it. Whereas in JavaScript, it's a discipline. You don't get it by default. You have to do it. So you get to see all the work that it takes to use immutable data. Basically, you do a copy on write or a copy on read.
Speaker: You have immutability. And so now you understand it, you understand the cost of the discipline and the difficulty of doing it. Okay, now you're going to appreciate when you go to closure and have to use it. Is that how it works? I mean, is that the feedback you're getting? Because I'm interested whether people, because like you say, if people are having to suffer pain, people don't like that, you know?
Speaker: But I guess what you're saying is you can, you can, you can see it from first principles maybe, you know, so yeah, there are libraries that help you out here and there are other languages that can help you out even more, but actually this is like the, like a first principles kind of model. It is a first principles model and it's also like.
Speaker: You know, I say it's like getting back to basics in functional programming. I would be happy if people just could identify mutation.
Speaker: Oh, this is unsafe to call because it's going to change the JavaScript array I pass it. If they could know that, or like, oh, I can't hold on to this thing because I don't trust that something else that doesn't have a reference that's going to mutate it. If they could do that, that would be a huge win. So if people start putting lines at the end of their function names, that's already a start basically.
Speaker: Yes, exactly. Just be careful. You can do it. Here's the rope. You want to hang yourself? Go ahead. But it's that kind of thing that I really think that other books don't talk about. They just do not spend any time. They don't spend enough time. Like I said, they might be a sentence, a paragraph, but they don't spend enough time for
Speaker: beginners to realize like, for instance, that the plus plus operator actually does three things. It reads the value out, it adds one to it and it stores it back. And so that's three things happening. One of them is a calculation, the adding, right?
Speaker: But the other two are actions and you can interleave another plus plus operator and another thread between those. And it, uh, you know, gives you weird mistakes that only happen sometimes. The funny thing is I remember, I remember reading that, um, swift does not allow plus plus. And they had a, they had a very long like discussion about this because they were saying, yeah,
Speaker: Exactly to your point, you know, is that it has all these magical properties that cause a lot of unknown bugs. And so, yes, it's convenient. Yes, it is sort of expressive. But actually, it's just too dangerous and too buggy. And the things are not what's going on is not obvious enough. So they actually disallow it, which
Speaker: I mean, you could disallow it or you could make it an atomic operation. You could say, well, if you're going to do it, we're going to put a transaction around this and nothing else can look at this variable in the meantime and it'll slow everything down because it does look like it's a single thing.
Speaker: Coming back to the, so the book is called Grocking Functional Programming. Grocking Simplicity. Simplicity. My brain already linked simplicity with functional programming. The interesting point about that actually is like, where does the simplicity come in? How do you, how do you, I know, sorry.
Speaker: I probably need to go through and just use the word simplicity a lot more in the book.
Speaker: It's kind of just like a historical accident that it's called grokking simplicity. It probably would have been called grokking functional programming, except they already have by that title. I think it's a good rebranding of functional programming because I think functional programming is terrible, like I said at the beginning. And I think simplicity is much better.
Speaker: because that's really what you're trying to aim for, clarity, simplicity.
Speaker: Yeah, and it's another aspect of the closure influence that I was talking about. Call back to closure, yeah. So yeah, the simplicity is all about pulling functions apart into more reusable pieces.
Speaker: It's about the complexity of having so many actions and they can interleave, right? And so the complexity is like, how many ways can they interleave? So it's a quantitative thing. If you have two actions in each thread, there's, I think, six ways they can interleave, something like that.
Speaker: But what about JavaScript single threading? Because that's what people will say about JavaScript as well. Don't worry about the threading because it's all fine.
Speaker: And they do say that, don't they? The problem is once you have Ajax, you have any kind of asynchronous call, then you're back to, I mean, they're not threads, but they're different timelines because you will chain an Ajax call after another one and after another one. And that's, there's multiple of these chains happening at the same time. And you don't know when each one is going to be called. The callbacks are going to be called.
Speaker: Then you also have this other problem of stuff is happening on the server. You read a value and you think it's current and you add 10 to it and send it back. Well, what if someone has already changed it? You need to be thinking about this in a distributed systems world.
Speaker: So functional programming has been sold as like, we're going to need it because of multiple cores on our machines, right? Yeah. And I mean, it certainly helps with multiple cores. That's not untrue. But we were also promised like thousands of cores by now.
Speaker: Like 10 years ago, it's going to double every year. And it hasn't. We have like, what, 16? 16, yeah. We are, though, facing all these distributed programming problems that we weren't facing or we weren't maybe aware that we were facing them 10 years ago. We didn't have so much Ajax. You would even have just like one database and like
Speaker: Now we realize, oh, we've got a client running on every browser and we've distributed our application to all these microservices and each one has its own database and they have to sync up somehow. And this is where functional programming and this why it's actually being used right now.
Speaker: It's not going to... The scope of functional programming is not going to go across these boundaries of systems, right? Right, no. But how do you see that then? Because within the system it makes sense. Yeah, functional programming does not give us a model for programming the cloud, right? Yeah, exactly. What it does is it gets us to ask the right questions.
Speaker: It says, oh, this is an action, even though it seemed like I was just reading something from the database. That was actually a message that got passed to a different machine and the database interpreted it and sent back an answer. So it's actually two messages. Object -oriented programmers don't think about that.
Speaker: I mean, they do, they do. When they get to a certain maturity, they know this, but they're not thinking of it as part of their paradigm. They're having to learn it, but it's not part of the paradigm. And in fact, a lot of object -oriented programmers, if I could generalize, they try to bury it. So they'll take the ORM,
Speaker: and they'll wrap it around the database and then maybe add another layer on top and think that that's going to make the difficulties of dealing with mutable state go away. It's going to like, oh, it's going to give it a nice interface. But like, no, what you need is to pull it out.
Speaker: You need to not wrap it up. You need to separate out the stuff that is dangerous, you know, the mutation and, and you still have it. You need the database, but then separately you have like all the business logic and stuff to keep it, keep it pure. So just, I mean, I think you do talk about this in your podcast at least I'm guessing it's going to come up in your book, things like, um, idempotency, for example.
Speaker: That seems to me to be a kind of answer, if you like, to the distributed database problem, because you need to know that actions can be repeated, essentially, or in your case, calculations can be repeated.
Speaker: Actually, which do you think? Actions, you need to be able to, you know, I mean, the example I give is you want to send an email exactly once, right? You don't want it to zero times and you don't want to send it twice. And so if you don't get if you don't hear back, you make some HTTP post, and it gave you a 500 error.
Speaker: Like, did it send the email though? That's what I really care about. And you can't know, like maybe it timed out and you never received it, but maybe the server crashed after it sent the email, right? Or the network got moved down before the request came. Like, you don't know. And so the answer, you know, for robustness that you need in a distributed system is to be able to send it again. Send the same request again and assume that they will remember, oh, we already sent this one and we won't send it again.
Speaker: And so that means you need the action to be idempotent. So yes, that's an action being idempotent. What about transactionality? Where does that fit into your scheme?
Speaker: So in the book, we are going to develop transactional, sort of like a closure atom, but that works over asynchronous changes. So you might do a read and then do some AJAX request and then use the value from that to do a write back into it.
Speaker: And so it's got to be transactional across that whole thing. So basically, you have to queue them up. You just have to wait for everybody. We're going to do the regular atom, but that's easy.
Speaker: in JavaScript because there's no threads. So the ordering is straightforward because it's just single -threaded ordering, so you don't need to worry about the ordering problem. Yeah, exactly. The ordering happens automatically as long as you don't have any asynchrony. So you say if you pass a pure function to the atom, it's going to take the current value, run the function on it, the return value is going to be the new value.
Speaker: So is this, so grokking simplicity, is it now available as like a beta book or something? Before we get into that, let him pimp it out a bit later. Let's carry on with some of the technical discussions. Hold on a second. That's an insult to this podcast.
Speaker: No, I mean, the thing I was going to ask you about was another thing to do with functional programming, grokking simplicity, where maybe it's kind of at odds, but I'm interested in your thoughts about this is high order functions because
Speaker: me, higher functions. I don't know if they're undersold or oversold, to be honest. I do use them most days, my self -inclosure, but obviously with mapping and all kind of stuff. But also, I will write programs that take functions. But I rarely return functions, to be honest. But I'm just wondering what your take on the higher order of higher, because obviously, it's important when you're talking about functional programming.
Speaker: Or is that something that you lied or is you focus on this concept. Good question. So higher order functions I think are really important. They are the focus of the second part of the book. So the first part, the idea is just let's just identify actions, calculations and data.
Speaker: That's where it's sort of like, what's the biggest bang at the level that they're at? Biggest bang is like, know that that is unsafe. We can't do that willy -nilly. We have to put some boundaries around it. And then the second big bang is, well, you got these first -class functions. And so what can you do with them? And so that's an introduction to map filter and reduce.
Speaker: It's also an introduction to higher order actions. So this is stuff like being able to pass an action to a queue to make sure that only one gets run at a time in the right order, right? So you want to introduce the declarativeness of actions so you can declare and then execute them. Right, exactly.
Speaker: I think that's a hard concept for people to know that you don't have to send the email. You can have a function that will send the email and you can call it when you're ready. That is exactly the mindset shift that has to happen to get first order functions.
Speaker: But in day -to -day life, we are used to this one. If I make a list of things to do, like go to the market, buy milk, then go and get a tram, then it doesn't mean that immediately by reading the second one, I'm going to get the tram first. But you see, what happens is when you write the program,
Speaker: Yeah you are already at one level of running removed right so i'm writing the program to x do i do z that's my main right. People think that's it like i've already paid that and send everytime i run this program it's gonna run everything.
Speaker: What they don't realize is they can do it again inside the program and make it so that this thing is going to write the list and return it and this other thing is going to run the list. That's the shift that I think you need to, that people will need to make. It's going to be like a lot of people get map filter and reduce. They understand,
Speaker: how to use it practically or have a list and I want a different list. I'm just going to run a map over it.
Speaker: But what they don't understand is how much can be done as a total pipeline. All your work is done as chaining, map, map, filter, filter. You can do almost the whole program with that. And so we're going to focus a lot on that. We're going to focus a lot on the actions side. So that's just the calculation stuff.
Speaker: The action side, these chapters are actually mostly written. So this is a thing I have about functional programming. Everyone talks about pure functions and how great they are. But I think we have, as functional programmers, we have a lot more to say about actions.
Speaker: and mutable state and like you were talking about idempotence, Ray. I don't know of object -oriented people saying this, right? They're talking about stuff like that. We have a whole array of things that we know are important, transactionality. We
Speaker: We don't give ourselves enough credit that actions are a first -class part of our paradigm. Impure functions are part of the paradigm. It's not just pure functions. We're not just avoiding actions. No, we are treating them in a special way because they are so volatile, so dangerous, they're the source of bugs. And so we have all these things that we do to
Speaker: Maintain the order between two actions in different threads. At least make sure that they don't happen at the same time. One has to go first. We discredit ourselves. There's a lot of good stuff in functional programming languages that help you deal with actions.
Speaker: So one of the things that, I mean, this is like, let's say in the closure world, at least it's caused a bit of controversy recently with spec is this speech by Rich about speculative. I think maybe I don't remember the talk actually, but it's where he says that the optionality is a problem. And that's why we need spec too.
Speaker: We were joking earlier, by the way, that Speck started at the same time as Deafen. So it's kind of interesting with Speck about the same time that we're experimenting with podcasting. And they've got Speck too, and we've got Eric too. So maybe it's kind of... I'm out of alpha there. We've got him back.
Speaker: Right, yes. To make it better. We know what functioning is now. But what I meant was that, like, so is something like, because, you know, you say, you say it's like the optionality. How do you how do you know if things have worked or not? You know, that's the classic functional thing. There's like, you know, it's it's the option thing, the monad, you know, it's like it's something, it's nothing. So how do you how do you tackle that kind of thing in the book? Or is that a sort of
Speaker: version two or chapter three or whatever it is. So, um, I am going to get to that in part three, some, some form of data modeling. The problem is though, you know, to answer your question, the reason is hard to answer your question is that that is the furthest part of the book. That's the last part. And I haven't, it's optional.
Speaker: Yeah, it's maybe going to happen. No, I don't know what I'm going to say. Well, I don't know the specifics. To bring it back to simplicity, the thing about data modeling is that it makes your program simpler when you get the data model right.
Speaker: So if you have a correct data model, you have fewer if statements. And if statements are multiplicative of complexity. So if you have two if statements in a row, if you count the number of paths through those two if statements, it's two times two because it's two branches in the first if times two in the second if.
Speaker: And if you get your data model wrong, that means that you have to kind of reassemble, like figure out what you really have. So the example that you can give all the time is like, well, what if you have two Booleans?
Speaker: but you only have three possible states. Two Booleans can represent four states and you only have three. So here's an example. I used to work for a company and we had a workflow engine and something needed to be signed off by two people. So we would have a Boolean for the first person signed off and a Boolean for the second person signed off.
Speaker: But that doesn't really make sense because you could in your code with a bug put the second person has checked off and the first person hasn't checked off yet. That doesn't make sense. It shouldn't be representable. A better model would have been nobody has signed off or one person has signed off or two people have signed off.
Speaker: And that way, there was no fourth option that's not representable. Because if you have this, now you have to check. And so that's another statement, and it just multiplies your thing.
Speaker: I mean about I think Zach Telman's tweet or somebody retweeted Zach's tweet like every Boolean eventually becomes an enumeration. Right. Exactly. Yes. And they say the same thing in the Haskell world. You know, they say you're using a Boolean, but you might need
Speaker: And so what are you going to do, wrap it in a maybe? Yeah, it's one. And it's like, no, you need a new type. A common complaint in Haskell is everything you do requires a new type. About optionality, just for context, Racheke was talking about the maybe type.
Speaker: And how it didn't solve the problem that he wanted to solve, which was a program that will evolve over time. And if it evolves to where.
Speaker: An argument is not needed, but still acceptable. So it's optional now. In a language that would you, if you, if you use Haskell, you would need to now wrap that in a maybe, but that's a type change. And so that requires all the clients of your API to change.
Speaker: And there's various workarounds and I've talked to Haskell people and they say it's unfair. And I think that it's not unfair. He was complaining about this one type and that is a limitation of the type and we as an industry need to learn to accept
Speaker: limitations like that. It is a true statement. Whether there's workarounds in the language or not. He wasn't talking about Haskell is bad or anything like that. He was just saying, this one type has this limitation and we should recognize that.
Speaker: which I agree with completely. I don't know what else to say about it. I think that maybe is a good thing for modeling. If you do know what I want to say, you have a fixed domain that you're modeling and things don't evolve.
Speaker: but it has to be where the optionality is baked into the domain. Do you know what I'm saying? It's not where you're like discovering whether it's optional or this thing might evolve. And so you don't know whether you're gonna return it or not. It shouldn't be used for stuff like that. I think one of the problems, I think that maybe it's Haskell
Speaker: that people have got a point about is that a lot of closure programs are not monadic in this sort of Haskell -y sense. They're not optional. You've got these, like you were talking about earlier on about these data pipelines. And you can map this, filter that, do the other.
Speaker: And it's all great until suddenly you get an old pointer exception in the middle. And then you're fucked. Excuse my French. Might as well get a fuck out in the end. I know. It's been like over an hour. I don't know what happened. Usually it's like the first 30 seconds. Yeah, I think we were recording at that point when VJ got out. I told the magical words to open this podcast, yes.
Speaker: Yeah. So what I was going to say was that, you know, that's, that's kind of like that, you know, and I think people do get upset about that, you know, when they sometimes leave closure because of this evening, I get so upset that they get these no pointer exceptions and they're just like, they're going to fuck it more. Forget it. I just can't take it anymore. I can't take tracking down no pointer exceptions. Um,
Speaker: If I'm honest, I think closure is annoying in that respect as well, that it doesn't give you more context. I think this is a solvable problem by the compiler.
Speaker: But, you know, we always joke this about Apropos, you know, is that, you know, I think they once said that a closure is optimized for correct programs, but it's not optimized at all, in my opinion.
Speaker: I know the emails you're going to get. We don't listen to people's feedback at all. That's what we're trying to say actually. If we listen to people's feedback, we wouldn't still be doing this. Come on. Exactly. I think they told us after the first episode, what the fuck is this? Stop it.
Speaker: But now we are here after three years, 56 episodes. So, you know, we might as well get on with it. We will take guest requests, that's all. Anyway, so coming back to optionality, you know, I mean, you know, I think one of the nice things about this show is that we are able to just, you know, voice, you know, real talk, if you like, you know, then it's a problem with closure, in my opinion. It is.
Speaker: we might as well just put it on the table there. It's fixable, and I think they've acknowledged this, it's fixable with a development version of the compiler or some sub -optimal performance. You could fix this problem, but they don't do it for every, that's up to them. There are engineering efforts and costs and trade -offs and what gets first in the QS, et cetera, blah, blah, blah.
Speaker: But the point is it's not done, whereas in other programming languages, it is done. So you don't get this random null pointers in the middle of a pipeline. Sure. Or if it's in a language like Java where you still have a lot of null pointer exceptions, you're not doing some super high order operation.
Speaker: where you're looking at the stack trace, like, I don't know where my code is, and where the compilers, but the built -in map. You're doing a map except it's lazy, so null doesn't get you until later in your code. And the function that you pass is an anonymous function, so it doesn't have a name, it just has a number, and you're like, I don't know what function that is.
Speaker: But this is a problem in Haskell as well, right? The laziness adds additional complexity to this problem. Yeah, I mean, you don't have this exact problem because there's no null in the language. Yeah. And I think that that's another thing to tease apart. I had to do this myself. I was very confused. Haskell, it's not the type system.
Speaker: that is protecting you from null pointer exceptions. There just is no null. There's no value called null. Because they don't have a null, but they want to represent optionality, they have maybe and other stuff.
Speaker: So then the problem is the maybe brings back a lot of the issues with null. Like you might not have a null pointer exception, but if you have a nothing, you don't know where it came from. If they're chained together and you're using maybe as a monad, like somewhere in that chain,
Speaker: It became a nothing and then the rest was just skipped. And so it do have like these similar problems. You know, people will say, yeah, but at least you knew that that was a positive. Like I don't, I don't buy that. I knew every, every line of code I have could have no pointer exception. You know, I sympathize with closure programmers because like, especially new people, like I don't get them that much.
Speaker: And so it's one of these things like I've developed all these disciplines that I'm not even aware of anymore. It's always in the back of my mind, what happens if this returns null? Is it going to fall through? Is it going to do something? Is it going to do the right thing basically if a null happens?
Speaker: I find that the closure built -ins do the right thing. Sometimes they don't, right? So you can't always just check, the classic is I'm going to filter for identity, right? But what if there's Booleans in there and there's going to be some falses? So now you're mixing the nils and the falses, you're throwing them all out. So now you need to think, oh, no, I need to filter nils out. So nil question mark.
Speaker: or I guess you would remove nil question mark. So there's things like that, these little habits that I have that I don't even have them conscious enough to just list them. But I do have to say over time, you don't get them as much. You've got a nil sympathy.
Speaker: I mean, for me, it is not that much of a problem. I know you're just, but for me, it is not a problem that requires like, Oh, maybe I should go to another language. Like, it's just not that level. Yeah, yeah. It's a trade offs, right? Because the other advantages that you get with the mutability and the
Speaker: and the way that you can fluidly write code. I think it makes sense to have some, I mean, we are saying that Clojure has its flaws, but they're completely manageable. I think the difficulty with Eric's point of view though, and I agree with it, that you can develop certain habits. I think the difficulty of it is when you're in a team and you've got like five or six people all committing code and they haven't got those habits,
Speaker: And maybe you're not very disciplined in your PR process. Then you've got issues, you know, because then other people are like, they're not exactly breaking your code, but they're putting the possibility of nulls in there that you don't know about. And that's, you know, I mean, I know that you do a lot of work on your own, Eric, for books and for podcasts and stuff like that, but you also do consulting, so.
Speaker: I think a lot of us do work in teams of three, four, five people, and then it has to be named. You have to be able to do things in a certain way. That's true. I totally agree with that. And you want to be able to have, let's say, a junior new hire and fresh to closure contribute.
Speaker: And if you're just always worried that they're going to be introducing null pointer exceptions because it's so hard, they don't have all the disciplines yet. It's nice that our conclusion is that it's other people.
Speaker: I'm paraphrasing, of course, but you know, like, you know, what is the other people mostly? I'm fine. Fuck it, you know? Yeah, I mean, and who was it? It was, what's his name? The guy from id Software was giving that talk on functional programming for a while.
Speaker: He was learning Haskell and Scheme, and he said he really liked Scheme, but the reason he would do Haskell is John Carmack. Yeah, John Carmack, yeah, thanks. He was saying that with a sufficiently big team of developers, every bad habit is going to come out.
Speaker: Exactly. And so you want as much, you know, help, you know, this is the kind of company they're writing in C and C++, they buy those million dollar like bug finder packages, you know, that like do static analysis on your code and tell you, Oh, this for loop, like, it might, it has this one case where it might skip a, you know, and like go into an infinite loop, like, they, they,
Speaker: are investing in that. And so something like Haskell to them is much more like, well, let's give the programmers a little, let's put this closer to the programmers so they can solve their own problems, not catch it later. I have also heard really smart Haskellers say that the reason they like the type system is because they can be like,
Speaker: you know, a Kung Fu black belt level Haskell person and develop a type. So they invent a new type that's like a monad with stack. Like they make the type that they know is correct. And then at least they know that no one else can do harm.
Speaker: It's a way of multiplying their knowledge out because now it's in the code and the compiler is checking it. Even if they can't, they might not be able to figure out how to get their code to compile, at least they're not thinking they got something right and pushing it to production. I have to sympathize with that in the practical sense because I have been on teams like that where
Speaker: Most people were working at a very high level and then the juniors were not able to contribute because the stuff was just over their head. I mean, the stuff we were doing was like high level closure stuff. And every time they would contribute something and pull requests, the comments would be like, oh, this is going to crash in this case, in this case.
Speaker: And it was just too much. It was too much. We weren't getting anything good out of them. And, you know, it makes you think like, well, that's why everyone wants senior closure programmers. It's like... Yeah. Everybody, I think closure is seen in people's code or seen in people's programming language. And it almost sounds like, you know, you get to use after you're 65 and you get some discounts and shit.
Speaker: Even the stuff like an atom, a simple atom, the contract is pass swap a pure function and it'll be fine. That's it. It's not much to think about except what if you don't? I don't even know what happens if you don't. I always pass it a pure function. What if it does a def inside that function?
Speaker: Like what is going to happen is going to be called? I don't know. And that's, that's the kind of thing that people do when they're first learning closure. And that's, that's totally fine. It's just, you know, nothing's checking. But I think, I think that in this case, I think, you know, there are, there are sort of, uh, levels of, uh, checking that you can do, like, I think like the CLJ Condor stuff and the other bits and pieces that, you know, the, um, the linters.
Speaker: They're definitely pretty good. But like you say, there are certain interoperability things where nulls can creep in or certain use cases where a certain function will produce a null but other variants will not. They're very slippery. They're very difficult to encode necessarily because one isn't necessarily wrong. It's just wrong in a certain context. And people are used to languages that
Speaker: Um, well, okay. I have to say it's similar to JavaScript where there are parts of the language that are like no, no, don't use that. Um, and there's a lot of stuff that you kind of have to use cause it's, there's no other option. So you have to like become an expert at this, like what are all the ways that, you know, this can go wrong.
Speaker: What are all the ways that you can abuse the plus operator and get weird values out? You have to know this. You know, there's stuff like - Equals and equals equals and equals equals. Right, you have to use equals equals equals everywhere, not the double, double, double equals. I think that what we have and that I have internalized and don't,
Speaker: don't think it's that big a deal, but it probably is, is very similar to in JavaScript. Yeah. Yeah. So we still need discipline. Yes. Whereas in Haskell, um, I mean, you know, I guess you could say at least you don't have that. I would love to see though, a bridge between the, the untyped and the typed. I would love to see, um,
Speaker: I would love to see more experimentation in type systems. When Rachiki gave that talk, it was called Maybe Not if you want to look it up. One thing that I think got overlooked was he actually showed an example of a type system that did what he expected.
Speaker: So it was in Kotlin that in Kotlin you put a question mark after the type and it makes it an optional, which means it allows nulls. But it's checked by the compiler. So if you don't check for the null, then it'll complain to you. It won't compile. It won't break the clients. What's that? It won't break the clients. Right. If you add a question mark,
Speaker: It doesn't change the, uh, the, uh, the clients. They don't have to change any of their code because they were already passing it. It's, it's optional, but it's accepted. And so they're fine. And I think that, uh, what do I want to say? Like that kind of statement, even though he made it and it was very clear and there were slides about it.
Speaker: It just like people just totally overlook it, right? They want to focus on like, why are you bashing on Haskell? You know, Haskell is this and Haskell is that and it's good. It's like, I know the level of discourse we have is just so bad. And I want to see more of that. I want to see more.
Speaker: I guess developing type systems with practical use cases in mind. And I think that that Kotlin example is a great example of what I'm trying to say. It's like these people are writing a language for Java Interop. They know that there's going to be nulls everywhere.
Speaker: It's just the nature of Java and they need them. They need null sometimes. And so they developed a type system that had a very practical, like the type system itself has a notion of null. Whereas in Haskell, like I said, there's no null. And so they used, you could write maybe.
Speaker: You could write it yourself in Haskell. So it's not built in. Anyway, I'm rambling now, but I would like to see a bridge. I want Haskellers or type theorists to work in an untyped language and
Speaker: and see, Oh, I see it. It gives me this freedom that I didn't have in my type system that is actually really useful. How can I take this back? How can I make this safe? It's always a kind of, I mean, you know, we, we have like functional programming meetups and you know, we always, you know, we look at Haskell talks and Elm and stuff like this, but it always ends up boiling down to productivity versus correctness or like,
Speaker: You just want to be able to experiment with something. You want to be able to explore something. You can do that in Clojure very easily and JavaScript as well. But in other languages, more type languages like Scala and Haskell, there's a lot more formality around getting things right before you start programming, before you start playing with things or experimenting with things. And I think that's a very difficult
Speaker: what should we say, bridged across, you know? Yeah, I agree. I think that, so like Haskell, I mean, what if you had an unsafe Haskell? Like, what if you had an untyped Haskell? So you defined a semantics for what it's supposed to do.
Speaker: without the types. It just made it a dynamically typed language similar to Clojure. It's meant to be an experimental ground for compilers, so why not?
Speaker: Yeah, exactly. And so you just define, look, this is what it would do. Uh, and so now we don't have to, we could run it without checking the times. Now I know that the Haskell does have a thing where you can run it without checking. That's not what I'm talking about. I'm talking about like actually being at a REPL, being able to, to like construct Haskell, uh, you know, expressions, get some Jason from some random API that you know very little about.
Speaker: and start working with it. It's without knowing the types. You don't know the types yet. One thing that people bring up when I wrote an article a couple of years ago about how Haskell is difficult to work, it makes it hard to work with JSON because you need to fully type it before you can, and it's not,
Speaker: People say, well, how do you work with JSON where you don't know anything about it? And that's not the point. You do know a lot about it. It's just how difficult is that to express in the type system.
Speaker: I know that I work with say the WordPress API and it gives you JSON and it gives you sometimes like if there's what we might call a null, well sometimes it gives you false and sometimes it gives you an empty array. So it gives you null, false or empty array and these are all kind of equivalent. Well, how do you express that in Haskell?
Speaker: Like, this is the kind of thing that, you know, or it'll say, well, if we have this key, then this other thing is going to be of this type. But if we have this key, and it's a number, well, then this other thing is like, okay, we know a lot about it, we could express it in English, but how do we express that in the Haskell type system? That's the kind of thing that,
Speaker: that I think the bridge needs to happen on. I mean, I will say it like this. It's probably wrong. It's probably a generalization. But the people working on Haskell compiler extending the type system are academics. They're probably not hitting WordPress API and stuff like that. So yeah.
Speaker: I think the solution is that don't use WordPress API. We can talk to you forever. You're going to have to come back in the third time. When the book is published, maybe. I hope not in two and a half years. Yeah, like one zero and it's out of alpha. We'll have you back. We can take that bet.
Speaker: I'm pretty sure you want me back next week, that's for sure. Yeah, for sure. So maybe I think it's a nice time to tell people where it can actually find the book. Now we finally get there, yes, okay. Yeah, so the book is called Grocking Simplicity. It's published at Manning. So if you're, you know, buying from, it's only available on manning .com right now.
Speaker: But if you go to lispcast .com slash GS for grokking simplicity, that'll take you right to the page. If you want 50 % off, I have a code. It's TS simplicity. One word. Just when you check out, you can put that in. It'll give you 50 % off.
Speaker: I think it'll also give you 50 % off of everything. So if you want to buy a couple other books too. Is that a special definite offer? No, it's not a special offer. I mean, even if it was a special offer, like it would just be a different code. 50 % off seems to be pretty common. So it is on the meet them. Yeah. So the first five chapters are out.
Speaker: I'm actually a little ahead. The Manning Early Access Program. Yeah, Manning Early Access Program. So if you buy it now, you'll get an email every time the new edition comes out. And so yeah, you'll get it all. And then you can even buy the print book now and you'll get the ebook
Speaker: So you'll get the updates as they come out. And then when it's finally printed, you know, just like, oh, look, I remember this. They're like, get it for Christmas for somebody, but you don't know when Christmas 2021. I think when you get the book, it's Christmas. Oh, there you go. I'm getting better at marketing.
Speaker: better sales person than me. Yeah. So go to lispcast .com slash G. Yes. For ghost art. Sorry. Rocking simplicity. Yeah. So that's where you can get the book. I think it's, wow, it's one and a half hour. I mean, time is just flying. I mean, we could, as Ray said, we could, we could talk for hours. I know Ray had all these topics built up, all these tough, tough questions.
Speaker: Yeah, I think that's what we ask here. Tough question. It's hard. Tough. Just a quick shout out to other things. So you do Apropo every now and then. So that's on Apropo YouTube channel. That's right.
Speaker: We'll put the link somewhere where you can see and, um, uh, where Ray tries to solve computer programs. Yeah, you can actually see it and then see how Eric and, um, Mike and who else is there already? Yeah, sorry. Yeah. So they can try to solve the problems. They try to solve the problems and then show you better closure code. And, uh, Erica, what is your podcast? Uh, lispcast .com slash podcast. It's called thoughts on functional programming.
Speaker: Yeah. So go and check out Thoughts on Functional Programming. I think eventually it'll be branded to Thoughts on Simplicity. So it's going to be there pretty soon. I hope.
Speaker: So that's it from us for this year. And it's been, I think, almost three years. And it's a nice, fantastic episode to wrap up our year with, with the repeat guest, Eric. Thank you for sharing all your time and all these amazing discussions. And hopefully somebody will pick up the idea of, you know, making Closure more Haskell -like or making Haskell more Closure -like. I've had that idea type system for Closure.
Speaker: But yeah, so who has the time? There is a time system for closure, but you know, yeah, these things are, these things have been trodden, the ground has been hoed before. So, you know, shout out to him.
Speaker: Yeah. Yeah. So that's it from us for episode number 56 and we'll be back in the new year 2020. You can have flying cars in Defin on 2020 for sure. Exactly. You can tune into it.
Speaker: Yes, I told him it's flying cars and flying cyber trucks and shit and whatnot. And yeah, and a big, big thank you for all our patrons and who have been helping us in covering the costs. And we look forward to your suggestions. If you have any complaints, just redirect to Dev Now and we'll be there to catch them. We'll definitely be hanging around in the void, yes.
Speaker: in an hour. Thank you. Thank you, Eric. You're welcome. Thank you. Merry Christmas and Happy New Year to everyone.
Speaker: Happy New Year and Merry Christmas!






