Mark Seemann, who joins to talk about Functional Programming and Haskell, is a self-employed programmer and software architect, book author, PluralSight author, public conference speaker, Humane Code Video author in Cleancoders.com.
Sponsor
Proton Text is a complete SMS texting solution built for the Lightning Platform, and by one of our previous guests Pat McClellan.
Main points
- Why does Mark move from C# to F# and Haskell?
- What is a pure function?
- Why is pure function friendly?
- Why is Haskell suitable for learning Functional Programming?
- The importance of Immutability
- Dynamic v.s. Static typed functional programming languages
Links
- Haskell language
- Mark’s Twitter
- Mark’s PluralSight courses
- Mark’s personal blog
- Mark’s Humane Code Videos
- Book – Dependency Injection Principles, Practices, and Patterns
Video Teaser
Contact Me
If you enjoy this podcast, please reach me out to let me know your thoughts or simply say Hello. My (Xi’s) contact info:
Take care, until next time :)!
Transcript
AI-generated, unedited.
[00:00] Our sponsor today is Proton Text, a complete SMS texting solution built for the Lightning platform by one of our previous guests, Pat McLellum. Here is reason number one that admins and users love this app. It's lightning smart. Admins can easily configure the one-to-one messenger component for private messaging or collaborative team texting using queues or shared phone numbers. And using has record ID, the component always knows where it is, which conversations you want to see, and which people you might want to text. Proton Text uses Lightning platform features and Apex logic to make the app intuitive and easy to use. It's not magic, just good design. Learn more at protontext. dot com.
[01:01] Hi, this is a continuation from the last episode.
[01:07] Hello, everybody. This is Xi Xiao. This is another episode of Salesforce Way Podcast. I just had a conversation with Mark Seemann about the OO, about the Solid Principles, and now we are back again in the second part about functional programming. Hello, Mark. Hello again. So I know your career is kind of interesting to me because you started with C Sharp, which is the Microsoft stack, and you switch to F Sharp, which is a functional programming language in Microsoft stack. And furthermore, you studied Haskell. Yes. Why do you do all these? Why do it with that? So, so F Sharp was sort of just like a a serendipitous thing that happened to me because. I wasn't really looking for anything else, but I I got into this I got this little gig by proofing and being technical editor on some of Manning's books, you know the the publisher. And one day they just asked me whether I would like to do some technical editing on a book called Real World Functional Programming by Thomas Butsic. And and I thought, well, yeah, I've heard about this thing called F sharp and functional programming, and I I was just curious, so I thought, oh yeah, okay, I'll I'll I'll do it. And so, being a technical editor basically just means you have to read the book and try to see if all the code examples
[02:37] make sense, and you know things like that. You are supposed to not understand the things, or you are supposed to not know the things before, because you actually they want to see if if the book actually makes sense to you. So, I read that one, and it's it's a wonderful book. Anyway, what what happened was that I read a lot of these things in about F Sharp and the F Sharp way of thinking, and. I just felt that this was just so much the way that I wanted my code to look like. It was just it's a much clearer and more precise way of expressing. Behavior than what I've normally seen. See, Sharp already at that point had got you know a few functional traits you know embedded into it. T here is this thing called Link Language Integrated Query, and all of a sudden, I sort of started to do you know use some of those features already. But all of a sudden, I you know that book just made it very clear to me where all of those ideas were coming from. It wasn't something that was just you know. Popped up, you know, out of the blue into Sharp. It's actually something that that built on, on a um on a long, you know, tradition or a long, um, school of of thought about you know programming in in in in general. So I just got really interested in it. So I started picking up F Sharp, and um, my brain was just permanently damaged from you know seeing this new way of of of oriented things.
[04:07] So I started, you know. Writing it completely changed the way I wrote C Sharp code, and then after a couple of years, I was just like, "No, now I'm just going to buy the bullet and go back to C Sharp because that's just you know it just doesn't it doesn't really make sense in C Sharp." Okay, and at that point, you know, fortunately, then the the tooling around F sharp had improved so much in in those maybe two years that it was actually pretty good being in F sharp, and so I did quite a few years of F sharp programming. But then I got interested in, you know, whenever you are trying to understand and learn learn about, you know, more functional ways of doing things. This other language called Haskell kept coming up.
[04:54] People would say, "Okay, but you know, if you really want to do it in the functional way, here's how Haskell does it." And then I thought, "Well, you know, it keeps coming up. Maybe I should have a look at that." If so, if and and the thing is, if Sharp is this very friendly, it's actually a very friendly language in the sense that it. It it gives you the opportunity to choose from different ways of doing things. You can do object oriented programming in F Sharp because it's it's sitting on the same platform that you know C Sharp is sitting on, and it can interoperate with C Sharp code as well. So it needs to have enough of an ability to consume object-oriented code, and also to express itself and or look like object-oriented code, because otherwise it couldn't interact with the rest of the .NET world. So you can do object-oriented programming in F sharp, and you can do functional programming in F sharp. So it gives you this very nice, you know, ability to gradually, you know, go from you know your object-oriented imperative way of thinking into something that becomes more and more functional. But it never really It never really you know slaps you or your fingers and say no you can't do that because that's not the functional way. It just says no okay that compiles cool go ahead be happy okay so it's very it's a very friendly language in that way. It sounds really like a Scala. Yeah, I think I know. Yes, yes, I know very little about Scala, and you know, I know it exists, and I follow some people on Twitter that or JavaScript, yeah, you know, which is also right.
[06:25] Yeah, everything mixed. Yeah, but but it's it's a multi-paradigmatic language, true. But I got more and more curious about okay, so what would real functional programming look like? And then Haskell is is interesting because it is strictly a functional programming language. You can't do object oriented programming in it at all.
[06:44] And if you try to do something that is not you know that doesn't follow the principles of functional programming, then the code is basically just not going to compile. So it's it's. The opposite of friendly. It is very. It is very restricted. But I thought you know, as a learning opportunity, I was just curious. I and I really wanted to understand what is this thing called functional programming, so I just started looking into Haskell to understand what that is, and. And I'm just, you know, I I think it's a wonderful language. It definitely has its its flaws as well. It's not a perfect language, but it's it's really interesting in the way that it's it's organized. So I I found that, you know, it took me a few years to, you know, when once I picked up F Sharp. In the first, you know, there was still a few years where I was thinking in in C sharp because I had done so much C sharp programming. So I was sort of thinking in C sharp, and then whenever I had to do F sharp programming, I sort of had to translate my C sharp thinking into F sharp. And then, you know, one day it it it sort of dawned on me that there was some sort of switch in my brain that had been clicked, where now I was thinking in F sharp.
[08:01] And then many years later, one day it occurred to me that you know, hey, I am actually now thinking in Haskell. So this is sort of this has now become my my basic way of thinking about programming. I am sort of thinking, you know, how am I going to solve this in Haskell, and then I can sort of translate it back to F Sharp or C Sharp, whatever. And t here is a t here is some loss of fidelity going on there because there are things you can do in in Haskell you can't do in C Sharp, but. Usually, usually, you know, once you arrive, and a way of doing things, it just it can often still make sense in in other languages as well. So, so, so Haskell is basically just a a.
[08:42] Thinking tool for me. I've never had anyone actually pay me to do Haskell programming. I've had clients pay me to do F Sharp programming, but Haskell, yeah, it's just you know for my own education, if you will. I see. Yeah. Okay. So in functional programming, because most of Salesforce developers, we are not so familiar with functional, and we just started to touch the the modern JavaScript parts, you know, Exx Ex Seven. And even JavaScript is not like a pure functional language. You can write it in whatever way you want to write. Yeah. So I keep hearing this term called pure function. So, what does that mean? All right. So, a pure function is. There's another word that has also been throwing around, and that's basically the same thing. It's called referential transparency. And we should probably talk about both, but let's start with pure. So, a pure function is is a function that that has to obey two rules. Whereas you know your normal method or your your normal procedure, there's no rules for you know if you want to print to the console, you print to the console or whatever else you want to do. But for a pure function, it must obey two rules, and the first one is that it must be deterministic. And the way that we define determinism is that if you give the function the same input arguments, it should always return the same value. No exceptions. Same inputs should
[10:12] always produce the same output. So that's that's determinism and it's very narrowly defined. Maybe if I give an example as a simple pure function would be multiply two. Yeah, that's a pure function. Yeah. Oh, that is. So I have an input as a integer and they always return this integer multiplied two. Yeah, that's a pure. That's a pure function because no matter always whatever integer you give, it always returns. So you so you are so you often see examples from mathematics because that's where the concept actually comes from. So you know addition and multiplication and and those basic parts of arithmetic are you know pure functions. But but you can have pure functions in all sorts of other things. For example, if you have a string, you want to reverse the string. You know if you reverse. Foo, you always get oof, and that's that's always going to be the same. You know, the string will always be reversed in the same way. So that's a pure function as well. So it doesn't have to involve numbers. It can be basically anything. But it sounds really dumb. I mean, just it's it doesn't do much. You always return the same thing, right? Okay. But but a pure function could be very complex. If you think about you know your basic cryptography, most of cryptography is based on functions. So, and you probably think about you know. Computing, let's say for example you want to compute a hash of something. That's a that tends to be a pure function. Well, you
[11:43] often you want to seed it with some sort of random number, where you say, well, we generate a random number and then we seed it with or we salt it or whatever we call it. I'm actually not a cryptography expert, but once we've generated the the random seed, you can say whatever else happens there is a completely pure function because if you give it the same input and the same Salt or the same random number seed, then whatever else happens inside of that cryptographic function. It will always produce the same value, so so the idea of having deterministic behavior has nothing to do with whether it's simple or complex. It's just that question, you know, does the same input always produce the same output? Is it reproducible, if you will? D A N F. Yeah. So so that's the one rule, and the other rule is for pure function that it can have no side effects. So, a side effect could be something like you know if you if you add a row to a database that's a side effect. If you delete a file from disk, that's a side effect. If you send an email, that's a side effect. Actually, if you change the color of a pixel on your screen, that's a side effect because it's not part of the output. It is something else that happens you know as a side effect of running the the function. If if that makes sense, okay. So we we we could say basically if we say if if by calling the function you change something in the state of the application or or the context around the application, if something if the state
[13:13] changes just by calling the function, then that's a side effect. But it has to, but it has to be something we care about because obviously the temperature of the CPU might change by calling a function, and and that's that's that's something that we don't care about. So we sort of have to figure out, okay, what exactly context? Yeah, there's a little bit of a of an interpretation of the context when we talk about what a side effect is, but. But basically, if you care about the side effect, if you care about whether or not an email was sent, for example, you tend to do that. Then that's a side effect, and pure functions can't have side effects. But so that that basically leads us to this thing where, if you have a pure function. You could actually do the thing where you said, well, if you knew what the input was, you could take and replace the function call with just the return value. So you could say, well, instead of having to always say, okay, what is it? The two plus two is, and you say, well, can you calculate two plus two for me again? Can you please calculate two plus two for me again? You know, instead of keep on doing that, you can just say, well, the Instead of having the expression two plus two, you can just replace that with four, and that's a cast. It's sort of like a cast thing, but that's called referential integrity, where you say the. The expression is this is basically equal to the result. You can so you can instead of actually doing the function call, you can just replace the the result with the function call, and that's
[14:43] not that's not going to change anything at all. So that's the idea of a pure function, and we just talked about some things that. That are not possible with pure functions because you can't, you know, write new rows to database. You cannot send emails because that's a side effect. So, then why do I do this? It's impossible. Yeah. So yeah. So it's impossible to write useful programs without having some impure stuff going on at this at the same time. So, functional programming is not about avoiding side effects. So you talked about separation of concerns in the previous conversation that we had, and it's a disciplined approach to how do you separate concerns. Because, for example, you might have one concern that is let's calculate the outcome of performing a business transaction. And we want to separate that concern from the concern of actually printing the result on the screen, or putting the result in a database, or putting the result in an email, and. By separating the pure functions from the side effects, it actually becomes fairly trivial to do those things because you say, well, okay, so the calculating the outcome of a business transaction, it's basically just a question of you know putting enough inputs into the function as you know normal function arguments, and then you wait until you get a result back, and you know the result doesn't have to be a number; a result can be a big. Data structure with megabytes of
[16:13] data, if you will. But as long as it's pure, no emails were sent while you did all of that, and no. As the Haskell example always goes, you know, no missiles were launched against you know the foreign country while you, you know, because you all. This one of the problems we always run into in more imperative style code. You call a method and you. Because you wanted to do something, but then you get surprised because it turned out that it also did some other thing. So, so just having this knowledge that if you know that you're that you're actually interacting with a pure function, that you you have you don't have to be afraid to call it because you know that it's not going to surprise you. It's the the worst thing that can happen if you call a function a pure function is that it's going to take a long time or it might run forever. We we don't know that. Okay. So it might you know use a lot of heat, but apart from that, you know nothing unexpected is going to happen. And that's just a very liberating, you know, feeling as a programmer. And and you just sit there and you say, "Well, okay, I know this is a pure function." And you say, I wonder, you know, what hap? What's going to happen if I call it? Let me just say, I'm going to try because you just return something. It just returns something, and if I don't like the result, I can always throw it away. So it's really, it's really easy, and and and it feels safe to experiment with code because you just say, yeah, nothing, nothing, nothing bad is going to happen here. But does it mean that in function
[17:43] programming you try to separate the pure functioning parts and the impure functioning parts? Yes. Yes. So you keep the boundary. As clear as possible, right? So that so that when you test, especially I'm thinking of the unit tests. So when you run unit testing for pure functions, it tends to be really easy. Yes, you just test what's the output, right? Yes, while. In the object-oriented, when we write unit tests, we always need to insert something into the database, make sure the state is exact there, and initiate the object, and then call the certain method, and then validate, like assert, to make sure the final state is exactly as what we want. There are four steps in our. Object oriented ways, yeah. But here in function programming, you only need to test what's the output with different type of input, different. Sort of imposed. Make sure that body's there. Yeah, yeah, okay. Yeah, so yeah, that's one of the reasons I really love that style. And and and these are these are ideas you can you know pull back into object oriented programming. So when I write my C sharp code nowadays, I tend to write a lot of the a lot of all the All the difficult decisions that I have to make in the, it might be business logic or it could be presentation logic, but whatever it if it is, if it's something
[19:14] that is difficult, I try to write those as pure functions because then they're really easy to unit test. But you know, for the reason you give, you you basically just have in a unit test to figure out. Okay, you feed some input into the function, and then you look at the return value, and then you check whether the return value. Which again can be a big, complex data structure. It doesn't have to be, you know, a primitive type. But then you just look at the return value and see is that what I expected? Is is the expected and the actual outcome? Are they equal to each other? And if they are, you say, well, yeah, it seems like it's working the way that it's supposed to be working. So, testing is really delightful with functional programming. That's that's one of and one of the reasons I really like them a lot. So we said that for function programming, we need to split as clear as possible the pure and impure parts. Yeah. Um. So because there are different function programming languages like closures, Scala, whatever, Haskell. Do they have different ways of separating the the two worlds? Yeah, so so Haskell and there's a few other languages, but but but Haskell and PureScript and possibly one other called Idris, and there's a few other research languages. They they do distinguish between pure and impure code at the compilation level, so. At you know, in those languages,
[20:44] if you try to call a if you try to call an impure function from within a pure function, that's just not going to be possible. You can't do that. That's not going to compile. In other languages, like in F Sharp, or you said closure, and if you want to do, you know, functional JavaScript, there's no there's no compiler to. Well, if Sharp does have a compiler, but doesn't it doesn't distinguish between you know pure and impure. So so in those languages, you sort of need to keep that discipline yourself. And and again, that's that's one of the reasons why I wanted to learn Haskell because. It sort of teaches you that discipline, and and that means now that I sort of figured out, you know. Until you sort of get the hang of it, you might sometimes be surprised by what constitutes. An impure, you know, function call or an impure method call. So, because it's not only you know calling a database, it might also be something like if you ask. We talked about this before. If you ask the system clock, you know, what what's the time or what day of the week is it? That is also nondeterministic. But you can easily do that because you know, if even if you have unit test coverage, you can say, well, what's the time? And if you write the unit tests in the In in a specific style, then that's still going to pass. But it's actually non-deterministic, and also you know just just generating a random number, generating a GUID or UUID. Now
[22:14] that's a non-deterministic behavior as well, but it's something you typically tend to not really notice, even if you're doing test-driven development, because you say, "Well, okay, just I just got back a random number, but sort of like what you expected." So it takes a while to actually discover that oh that's actually also not a pure function, and and the problem is that you know if you have a call to your system clock buried deep inside you know another function that makes that entire function impure. It sounds like you are pair programming with the Haskell compiler, which is the master of pure, impure functions. It's part, yeah, yeah. So, yeah, you could say that it's definitely a tool that keeps you honest. The Haskell compiler is, and is it because Haskell has this type system, which makes you have to write the pure. Function or let's say you have to separate the the two. The way that it's implemented in in Haskell is via the type system. That's right. Yeah. So so basically Haskell has designed the distinction between pure and impure in such a way that. If you try to call an impure function from a pure function, then the your code is not going to type check, and that means the compiler will reject the the code because it it doesn't it doesn't make sense, it doesn't type check. So because if you have a pure which calls the impure, then the pure function becomes impure. Yeah, you could say that's
[23:44] what happened. That this happens in F Sharp, or this would happen in Closure, or in JavaScript. If you have a function and you think it's pure, but in reality it calls some other impure code, then you know, you know, we're supposing that it calls the impure code in order to actually. Do something with the with the impure results, so it doesn't. You know, so what you could do is you could say, as a degenerate example, you could say, well, in F Sharp, for example, let's imagine that I write a function. I want to write a pure function. I Inside the function, I call the method that gives me the time right now, but then I throw away the the time, and and I don't make any decision on it. I just you know ignore that result. That would mean that you know. I could, I could throw away the method call to, to this current time, and it wouldn't change the behavior of my function. So, this is sort of like a degenerate example where you could say, well, you could ask it for the for the system time, but then if you don't do anything with it, then you could still regard that as being a pure function because it doesn't. Alter the behavior of the function. You didn't use it. Yeah, you didn't use it. So, and you can actually also do something similar to that in Haskell. If you actually, if you don't want to use the impure stuff, that would actually still be able to to type check. You can do that. But but as soon as you want to use the value for something,
[25:15] then in what would happen in F Sharp or in Closure or in JavaScript is that the function that you thought were pure. Now, it all of a sudden it becomes impure because you're calling an impure function and you're making a decision based on that impure function, and that means the function. You just thought was was pure. Now has non-deterministic behavior, and that makes it impure as well. And the compilers on those functional languages want to give you a red flag. In in a sharp or an enclosure, they're just going to say, "Well, yeah, okay." They're not they're not going to notice. That's on your own, you know, your own discipline to to discover that this is taking. And Haskell will really Haskell doesn't allow you to compile. That's that's not that's not okay. Okay, yeah, that's that's really cool. So it seems to me that in Haskell, when you write a a function and then the compiler tells you this is a pure function, then you can really put your Put your hand in your heart, saying that okay, this is guaranteed. It's a pure function. I can sleep well during the night. Yes. Okay. And you said it's guaranteed because the type system has go. So in object oriented system or languages, we have type systems like integer, map, collections, all those things. Those are also types. Yes. Right. Yes. Is it similar? It's.
[26:39] Yeah, it is similar. So, and then, then again, not quite. But it's it's not that too. That's not far. It's not that far apart. But the type system in in Haskell is much more powerful than what we typically tend to think about when we think about you know object-oriented languages like well, Java. Or I know a little bit of the Java. You know, again, so you tell me the the Apex language is a little bit like Java. Yeah.
[27:09] Because you know, types in in in object oriented programming are not only you know strings or integers, but it's also you know classes are also types. So we have you know types that are you know also complex types. But but Haskell can do some some some neat tricks that you can't really easily do in in in Shyshaba and Java. But but basically, the the problem is not so much. That the types, you know, the distinction between pure and impure is not so much because the type the type system couldn't do that in C sharp or in Java because they probably could.
[27:47] Basically, what you what you have to imagine is that the way that Haskell represents an impure operation is that whatever the Data you're interested in, whatever it is, it's sort of put in a box. If you can imagine, it's the type is called IO, and it's actually a generic type. And I also understand that Apex doesn't have a generic, so that makes it a little bit harder to do to deal with. But it could be of any type. So you could say, well, it's a box of you know just the base class object, and it could contain anything. So you could sort of imagine it like that. But so what happens when you call an impure operation in in Haskell is that you get this little box. As a return value, and the problem with the box is that it's opaque, so you can't see, you can't tell what's inside of it. It may have a label on on the outside. It actually does that says, "Well, here's an integer," or Here's a string, or here's your car object, if you will. So it has this label on the outside, but that's the only thing you know. So, for example, if you want to query a database and you want to get, you know, a collection of cars from your, you know, from your cars table, you want to query that database and get it back. So in Haskell, what you get back is something called IO of car. But the way we can sort of think about that is it's a little box with a packaging label on the outside that says. There's a list. There's a collection of cars inside of it, but there's no way to open the box. You can pass the box around to other functions and so on, but you can't actually
[29:17] look inside the box. The only way you can look inside the box is if you're already in an impure context.
[29:26] So this is really a smart design. Yeah, it's actually pretty clever. So what happens is that the entry point of a Haskell program is always impure. So that's your main method. You know, C, Java also has you know a main method. That's the entry point, and the main method is impure in Haskell, and that means since it's already impure, everything you get in those boxes that are otherwise opaque. Well, you can open them and look inside of them, but only because you're already in the impure context. You know the the box becomes transparent, if you will. But as soon as you pass that box around to a pure function, the pure function says, "Well, yep, it's I can't see what's inside of it, but it can pass it on to other functions." So, what you can do is you can actually take impure values and you can sort of unpacked unpack them in the impure context, and then you can sort of take your numbers or your car objects out of the box, and then you can pass them as argument to pure functions.
[30:26] And then the pure functions will do something with them and return their values, and then you can do some other more impure stuff with those as well if you wanted to do that. I think you made a really good analogy to make me understand this IO. It's a box, so that box guarantees that in the pure function inside the pure function, you cannot open it. Otherwise, that that the pure becomes an impure, right? This is guaranteed unless you your code execution enters the impure part, then you are safe to open it up. Yeah. But in functional programming, there are other important concepts that I often hear, like a higher-order function, immutability, all the things. So, are those things also important in functional programming? Even in OO, I start to hear that okay, let's do something immutability. You know, always return a new object instead of mutate. Right. Yeah. So, immutability is a very nice way to organize. Data in general, it it actually follows as as a it just it follows from this idea of pure functions and. I'm just going to skip a lot of the of the of the argumentation of exactly why that is, but basically once you adopt the idea of having you know pure functions, immutability sort of falls out of of that idea as well. But the idea is that you have a data structure that. Once you've created a particular object,
[31:56] if you will, in quotes, you can't change the state of that object. So we call that an immutable object, meaning you know you can't mutate it. So you can definitely do that in C sharp or in Java or in JavaScript, I suppose.
[32:13] Because it's basically just a a matter of not enabling the accesses that allows you to to change the object. I'm not so sure about JavaScript because it's so long since I did JavaScript. But but you can you can definitely do this in in in C sharp and in Java. So what?
[32:35] What comes out of that is to say, well, let's go back to we talked about in I think that was the previous discussion we had. We talked about you know how to model a car, so we can say well we can model a car as an immutable data structure, so it will still have you know. A manufacturer and a year that it was made and the color and whatever else we need to keep track of with a car, but once you have that data structure, well, you can ask it. Okay, so who's the manufacturer? Oh, it was Toyota. Or what's the color? Oh, it's a red. You know, it's a red Toyota. You can ask it all of those questions, but you can't change it. You know, once it says, well, this is a red Toyota, you can't say, it's blue. You can't change the red to a blue. What you can do is you can make a copy of the data you had, and you can say, "Well, I'm going to make a new immutable car where I take all the values from the old one except the color, and I'm going to set the color to blue." But then I'm going to say, "Well, the manufacturer is still Toyota, and the color is now blue, and the year still, you know, it's from two thousand and." Fifteen, or you know, all the other things you just copy over, except the thing you want to change. So that sounds. Like, why would that ever be useful? Yeah, because it sounds like it's more work, and you know you need to do more work in the CPU. So it's there. There are shortcuts that means that it's not that much overhead, but there's a little bit of overhead there. But one of the really interesting things that come out of having immutable data is that.
[34:06] First of all, a lot of of issues about multi-threading just go away because the issues you normally have with multi-threading is that you have you know multiple threads that try to change the state of the same object. But here you have objects that can't change state, so that means if you want to run computations on multiple threads, you can just go ahead and let them do that, and you can be you can just feel well. Okay. At the end, when all those threads complete, I need to figure out a way to you know to to synchronize or to combine all of the results you know back in on one thread. But that's the only problem I need to solve now. I don't need to think about all sorts of you know complicated threading issues that goes on you know while the computation is is running. So that's that's one huge benefit. Another really interesting thing about immutable data structures is that once you have a Data structure that's immutable. That means you can give it what we call structural equality, and that means you know usually when you compare objects to each other and you say, well, is this object equal to that object over there? You usually use what we call reference equality, where you say, well, if if you know if object X Occupies the same memory space as object Y, then it's the same object, but otherwise it's not. You know, reference equality is absolutely the safest way to implement equality when when you're talking about objects that can change.
[35:36] But when you're talking about immutable objects, you say, well, okay, we know that they can never change. So if we've compared, you know, all the values at one point in time, we say, well, Toyota is Toyota, red is red, and 2015 is 2015. Okay, these two X and Y, even though they have, you know, they actually live in separate memory addresses. Once we've concluded that they're the same, we know that this is going to be true forever, and that means we can just we can implement equality on those objects so that when we ask them. Are they the same? They'll just say, "Well, yes, they're actually the same," and that means comparing, you know, objects just becomes so much easier because you don't have to go and say, "Is the make the same? Is the manufacturer the same? Is the year the same?" You basically just say, "Well, here is what I expect it to be. Is that actually true?" And again, this is one this is one of the benefits where it. It becomes really delightful to write unit tests because you you probably written if you've written a lot of unit tests in a software in a program, I mean you you know that you often ending up writing something like assert that the expected manufacturer is equal to the actual manufacturer, assert that the year the expected year is equal to the you know the actual year. Multiple asserts. So lots of asserts that go all the way through, and it becomes even worse if you have you know. Objects with nested objects inside of them, and particularly if those
[37:07] nested you know objects inside of them are collections in their own. But with immutable data structure, you just say, well, here's the object that I expect. You just write that in your test. You say, well, here's the object that I expect, and it might be as complex as it needs to be. And then you say, is that equal to the actual outcome? And then because you have this structural equality, they just go and say, well, if all the values are the same, then Yep, it's good. They're the same. So yeah, comparing things just becomes so much easier. So so that's so multi threading, and then you know comparison of objects is probably the two main benefits of having immutable data structures. So it means it also brings great benefit to. OO languages. Oh yeah, yeah. It's just you can definitely do this in OO as well. It's just it tends to require quite a bit of boilerplate. You know, in F Sharp and or in Haskell, if you want to define an immutable data type. That is generally, you know, depending on how many constituent elements, it's just you know one line of code or two lines of code, something like that. Very, very compact code. And if you want to do the same thing in let's say this, just say C Sharp, for example, now I need to write, you know, define a class. I need to make sure that that the class has a lot of read-only properties or fields, so I can see what they are. I need to make sure that it has a constructor that takes all of those things and assigns them to the to the class fields. I need to go and override the equals method,
[38:37] you know, that so that it it doesn't do reference equality, so that it actually does you know structural equality.
[38:45] So there's a lot of things that that I need to do. So you know, with the latest version of Visual Studio, there's actually a lot of those things that can be automated, but but it still you know leads to. Even if it's auto-generated code, it still leads to a lot of code. Whereas, you know, in F Sharp or in C Sharp, it's just no. Sorry, or in Haskell, it's just you know one or two lines of code. So, types. This is one of the things that you hear F Sharp programmers say, for example. You know, types are cheap. But and what they mean by that is, you know, defining a new type, a new data structure, it's just it's just one line of code. You don't you don't even create a new file for that. You just put it in in a module, and a module is a collection of of data types and and functions. So yeah, so it's it's really you know the barrier to creating a defining new types in functional programming language tend to be much lower than you would normally tend to see in in in object or in the programming. But but I think one of the One of the things that I that I that I get from doing a lot of functional programming is that I, as an object oriented programmer, I become much more aware of the benefit of defining new types. Whereas you know, if I think back to how I wrote object oriented programming, let's say ten years ago, often it wouldn't occur to me to define a new class for a very limited little you know. Area of responsibility, because you sort of don't really think about types as being fine grained when you when you're sort
[40:15] of in the objectorian mindset. But now I do. So there are lots of of times now where you know even if I'm running in She Sharp, I think, oh. I know there's a little bit of overhead of introducing a new a new immutable class that should model this, but I'm going to do it anyway because I know how beneficial that's going to be. So it does change your mindset quite a bit. So I think that's one of the main reasons why it's it's really beneficial to to learn functional programming, even if your day job is writing in object or in the code. It it will give you new ideas, and some of those new ideas you can you can take back and and and use them every day. Hmm. All right. So, so Mark, I know that you have two books called the Dependency Injection and the Dependency Injection in C#. That would like to. Yeah, it's basically the same book, just two different editions. Yeah. Okay. Okay. And you have created multiple Pluralsight courses, including the Solid Principle encapsulation in the OO, and also multiple ones in F Sharp as well. How to write good coding F Sharp. That's true. Also, you have test. Driven related, how to write good test code. So I would urge our listeners to go to Pluralsight because most of us do have Pluralsight subscriptions. Why not to check your course for free? Yeah, yeah. If you have a subscription, then then it costs you nothing but the time. Yeah, so you are in contact with Uncle Bob, Robert Martin.
[41:45] I would assume because you know you follow each other in Twitter. I know he starts to write closure code, and he he really advocated closure. Yeah, is it because he start to see the beauty of using functional programming, or what's what's that reason? Just out of curiosity. So so he and I. Disagree quite strongly about you know whether or not closure is the best way or Haskell is the best way. We have we have long discussions on Twitter and blog posts and so on about you know. What makes sense to us in a friendly way, but but definitely heated but respectful. So I I can't really talk you know for him about why he thinks Clojure is is a great language. I tried teaching myself Clojure a couple of times. But I'm always put off by the its dynamic typing. It's dyna. It's a dynamically typed language, and and you know, once you that's my experience at least. Once you know how much benefit you can derive from this strongly typed language like Haskell, there's just There are categories of errors that are not possible to have in Haskell because your code couldn't compile, and then when I when I run into those types of errors in a language like closure. It just makes me want to throw it away and say, "Wow, this garbage!" You know, but obviously, obviously, it has its own benefits because there are things you can do in crochet that you can't do in
[43:15] a stronger type language, and so on. So, it's it's it's always a topic: the dynamic versus static. It is, and and and I'm I don't mean to disparage or to you know speak badly about closure. All Robert Simason, I respect Robert Simason greatly, and there's you know. Rich Hickey, who created Closure, is also one that has my greatest respect. So, it's. I think we're a little bit into the territory where it becomes subjective, and I am just saying, well, I just don't feel that I am the personality type that likes dynamically typed languages, and other people do. And that's also okay. I'm, I really would like to see the light. I would like to learn what it is that that they've. You know, it's not only Robert C. Martin. It's it's actually all the all the people that I look up to, like Robert C. Martin and Martin Fowler and Kent Beck and Michael Feathers. They they seem to be mostly doing you know dynamically type you know programming. So since all those Fantastically intelligent people do this. There must be something going on there that that I just I'm just too stupid to see what it is. I don't know what it is. So. Yeah, so so we have all those debates, and it's always it's always very you know engaging when we have those debates. But you should probably ask him about it if you want to. Yeah, I would do that the other day, maybe. All right, Mark. I think we did a great show. We talked a lot about OO,
[44:45] about function programming. I think we would definitely bring some light to Salesforce developers. Thanks a lot for coming to the show. Oh, it's a delight. Yeah, see you next time. Yes, goodbye.