Programming Throwdown - Functional Programming
Episode Date: June 19, 2019Hey all! Since episode 82, we received a ton of email asking for more info on functional programming (FP). To cover FP in great detail we are thrilled to chat with Adam Bell. Adam is the host... of the Corecursive podcast and an engineer with many years of experience in FP. In this episode, we dive into what FP is all about, when it's useful, static/dynamic typing (our favorite topic), and other areas of FP. Thanks again for all of your emails and support. It is a treasure to hear your inspirational stories and we are so greatful to be creating content for over eight years. Happy hacking! Show notes: https://www.programmingthrowdown.com/2019/06/episode-91-functional-programming-with.html ★ Support this podcast on Patreon ★
Transcript
Discussion (0)
programming throwdown episode 91 functional programming part two take it away jason
hey everyone so we we uh got a lot of feedback on our interview with Jonas Bonaire a few months back.
And a lot of you really wanted to know more about functional programming and really dive deep.
And I'm really excited that we have Adam Bell, engineering manager and podcaster.
He's been an engineer for about 15 years.
He's done a lot of functional programming in his career.
And yeah, we're going to sit down and have a chat about functional programming, about Scala, about a lot of these different concepts.
And really kind of dive deep, start from the basics, and get people kind of ramped up onto functional programming.
So welcome to the show, Adam.
Yeah, I'm glad to be here.
Cool, cool. Yeah, so what is functional programming?
So at its simplest level, it just means that you would construct programs only using pure functions.
And a pure function would be something that, like a function in the mathematical sense.
So it takes in inputs and it produces outputs and nothing else. So that means, you know,
no modifying of global state, no, you know, modifying data structures in place, no throwing
exceptions. And maybe the more tricky requirement is like no reading of user input, no writing of things into the outside world.
So that is kind of a high level of what pure functional programming is.
Yeah, yeah, that makes sense. I think one of the things that I always found really tricky
was exactly what you said. I mean, at the end of the day, a program is going to interact
with its environment. That could be reading from a file,
that could be writing to the network buffer or something like that. And I found that to be one
of the hardest things to grasp when you join it with functional programming. So it's sort of like,
how do you, you know, a file is kind of inherently stateful and it seems very natural to have this
global file because you only have one of these files on your hard drive, right?
And how do you get people from thinking in that way where they just have all of these globals for all of these environmental things that are literally global?
How do you get them from that mindset to this functional mindset?
Yeah, I mean, I think you can think of it as a design constraint that you place upon yourself.
So I think a common pattern you might see is having a very functional core of your program,
and then kind of an imperative shell around it. So if you're, if you have the file, as you're
saying, and you need to do a lot of transformations on it, you know, you may have, like, functions that are ostensibly pure that take in, you know, lines of that file and do
some sort of transformation. So they meet the definition. But somewhere at the outside,
you have some imperative layer that, you know, does the actual IO. And I think that it's a really
useful design constraint, because what you end up up with if you limit that imperative side effect D stateful code to the edges is a system that's very testable.
Like all the parts except that imperative stuff can be tested quite easily.
They just have, you know, for this defined output, do I get this?
For this defined input, do I get this defined output?
And so testing is easy.
Reasoning can be a lot easier in that world where you're kind of pushing towards functions.
So I think that it's a challenge, but it's certainly one that has a lot of value in my opinion.
Yeah, that's actually a really good way of looking at it. You know,
I think when I started working in industry, you know, through my, if you can actually go and look at my PhD code, it's, I'm not proud of it at all, but, you know, it didn't really have any
tests or anything like that because you're just kind of writing it by yourself and so one of the real
challenges when i got into um you know more of an industry role was was uh kind of realizing that
oh we have to really write tests because we're really depending there's other people who are
sort of depending on our code to behave in a certain way we can't really use a lot of our
own intuitions
and spread those through osmosis to the rest of the team.
And sometimes you find that after you've written something,
you go to test it and you realize it's impossible.
It can't be tested.
The only thing you could do is just test main, right?
Yeah.
And then you say, oh, well, I have to modularize this.
I have to break this down. And while you're doing that, you say, oh, well, I have to modularize this. I have to break this down.
And while you're doing that, you say, okay, I'm going to pull this function out and test it in
isolation. But to do that, it needs to be context-free, right? If you go to test that file,
that function, and it calls a global and crashes, you say, oh, okay, now I need to take that global
and pass it into the function so that I could pass in a dummy or something, a dummy object.
And what you're doing is basically you're learning functional programming.
So I think, yeah, a good way to get started,
if you've been going through some tutorials,
you're learning how to program and you feel pretty proficient
at procedural language, maybe C, C++, Java,
I think testing your code, even if, you know,
you might be the only person who will ever use it, testing it will be a really good exercise
in software architecture. And along the way, you'll be forced to discover functional programming in
one way, shape, or form. Yeah, no, I totally agree. And I think that it's been thrown at me before, like this statement. Hey, this, if your code isn't easy to test, then it's not good code. So I've, you know, people, especially like people who are really keen on test driven development will say this, but the problem I have with this statement is like, it doesn't really tell you what to do, right? It's just like, hey, this code is bad. So I think that some of these
functional principles can guide you in that direction to say, no, I mean, you can even
have things that are well-tested that just aren't good code because you have crazy mocks and stub
services and whatever. It's all pound defines, compiler macros. Yeah, exactly. So, I mean, to think about things as being pure
functions as much as you can, I think really guides you in the right direction. Yeah.
Yeah, that totally makes sense. So what are the functional programming languages that you use the most? So I spend my time in my day job writing Scala, which is kind
of, I guess, a multi-paradigm language. It supports like, you know, Java style object-oriented stuff,
as well as functional programming. And so that's where I spend most of my time. Huge fan of the
language. And then, you know, I am guilty of of playing with a lot of
other languages so i spent time teaching myself haskell and um that was certainly a great experience
and yeah yeah we had we had a lot of haskell at a place i used to work and um it's it's it's
interesting i actually really enjoyed it.
But part of the challenge was
we were building a software library
for other people to use at the company.
And so what that meant is
anyone who wanted to use this library
had to learn Haskell.
We found that to be really difficult.
And so we ended up having to rewrite
the whole thing in Python,
which is pretty sad because it looked pretty elegant in Haskell.
But this is just the way of the world.
Yeah, I think that Scala, because it is multi-paradigm, it can be used as sort of a better Java.
And so that maybe makes it more palatable.
And also, if you were building a library,
in your specific case,
there's nothing saying you couldn't use that
from any other JVM language.
So there's some benefits there.
I mean, the trade-offs are,
Haskell is a very hard line.
This is a pure functional programming language there's no
or very few like escape hatches i guess um whereas you know if you're trying to apply an fb style in
a language that doesn't enforce it um i think that requires you know like obviously if the language
isn't enforcing it then that's kind of up to the team to say this is a goal you know yeah exactly
i think if you're building a service you
can get away with it because you can write a protocol and um and yeah you know but if you're
building a library then yeah i mean the lesson i learned from that experience is is or really i
guess i wasn't the tech lead at the time but the lesson the tech lead learned is to really know
their audience um i think that part that that's kind of a universal truism
So you said you're doing Scala
I've seen Scala applied in many different ways
So it's used in Spark
Which is this big data compute platform
There's the Play framework
Which is kind of a web service
Are you using any of those?
What's sort of the scaffolding you Are you using any of those or what are you,
what's sort of the scaffolding you're using on top of Scala?
So we have one project that is a play project,
but we, I mean, it's more of our legacy product.
So we're building, I guess, web services.
And the main library that we're building i guess uh web services um and the you know the main library that we're using is called uh http 4s and it kind of is very much in the paradigm of of using scala to be uh
for functional programming and uh like it provides a really nice metaphor on top of of working with a web service so a like if i'm writing a code to respond
to some route that returns uh like some user information um that maybe gets aggregated from
somewhere um in http 4s with this kind of functional model i have a function that uh gets
in a data structure that represents a http request. And then the thing I return at the end
of the day is a data structure representing an HTTP response. So it kind of fits this function
model, data in, data out. What about contextual things like cookies? are they in the request object um yeah i mean cookies do come
in the request object and i don't think that i don't think that violates the uh like you're
still getting everything and you need basically yeah that makes sense so basically so the request
is sort of this uh multiplexer or this this this structure that has cookies as headers probably
has the then it also has the body with the actual
if it's a post request it has the body and then you can return some response that maybe has the
status code and the the body as well or something like that yeah and then you may further subdivide
this right because you probably want to take some sort of structured data out of that request and return some structured data and have
ways to format it. But at the high level, it's a very simple metaphor. A long time ago, I worked
in ASP.NET and they had this like page lifecycle model. And I remember like, you know, I wanted
to return that, you know, the status code was whatever, 409 or something,
and you write the code to return it,
but in fact, behind the scenes, there's some page lifecycle,
and it's already returned a response code where you are at, right?
So you had to understand this like,
oh, it's not just that I'm writing the things that return the body.
There's this lifecycle that lives outside of my code.
Oh, geez. And so that's the body. There's this life cycle that lives outside of my code. Oh, geez.
And so that's very confusing. And I think, I mean, most web frameworks don't work this way
nowadays, but I think it shows how like this functional model where you kind of get in all
your inputs and then get out all your outputs is much simpler than something where there's some
sort of, you know, extraneous information,
like in this case, that the header is sent, you know, by overloading some other method in the
framework or etc. Yeah, yeah, that totally makes sense. I think, you know, a lot of people might
say, well, you could do functional programming in any language. And, you know, ostensibly,
that's true. I mean, you could you could fit the paradigm. It might not look that pretty. So in the case of
Java, all of your functions would have to be objects that contain one method. But it's doable.
But the nice thing about a functional language is that, as you said, it might not completely
restrict you, but it makes it very easy to write functional programming
and it makes it more difficult to write this um sort of the procedural programming where you're
or just pure um yeah pure like recipe-based programming where you have all just global
variables and so it's like you can do anything almost anything in almost
any language but it's really you know the it's almost like being a an artist right i mean you
could paint almost anything with any paintbrush if you had the dexterity but certain paintbrushes
will make it very easy for you to do certain strokes and And so like any art, certain languages and certain frameworks
will make it very easy to craft your design in a certain way.
And the functional programming way is extremely powerful
as long as you aren't too dependent on, as I said,
a lot of these environmental things.
So a web service is a great example because effectively bits come in, bits go out.
And the only thing you really have to interface with from a real world standpoint is the network card.
But that's going through so many layers of abstraction that functional programming is a no-brainer there i think this a lot of this big data transformation
logic is also a really good candidate for functional programming which is why
you know sql and and scala now with spark and a lot of these languages are are functional because
they really excel in these environments yeah and uh like with spark and and data processing i think one reason it's a really
good fit is just like a you know if we talk about immutability that you're kind of um not changing
the data in place but kind of uh transforming it into a new uh into a new format uh that's very
like easy to split up and and and distribute across machines and stuff um
yep how do you deal with things like uh databases where you know database is this is this inherently
sort of mutable object yeah i mean so if you talk about like you you were talking about haskell um
and haskell has like this concept of like io where they kind of wrap anything that has an effect
in this IO type.
And then instead of actually performing the action, right?
The action is, it's not actually run until the end
of kind of the, like until you fall off the end of main, right?
It's kind of building, we're building up a program
that doesn't get run until the very end of main right it's kind of building we're building up a program that doesn't
get run until the very end of the world um and so that is a way i don't know if that characterization
makes sense but that's kind of a way to encapsulate uh making changes to the outside world while still
living in this kind of uh pure function world and so um what we do on our team is very similar. So we use like an effect type called
cats IO, I believe what it's called. So methods that perform an action upon the outside world,
like instead of having something that instead of having something that goes out from a web service,
let me think of an example. So I call a web service and get back an integer,
let's say, and then I need to use
that in some further computation.
So clearly, there's some sort of
interacting with the outside world there.
So how we would handle that is we have this IO type.
So instead of having this function that returns an integer,
it returns IO integer.
And this is somewhat similar to kind of like the async await pattern
that you see in a lot of languages.
Yeah, or a promise, I guess.
Yeah, so the key thing is that it doesn't actually run
until you tell it to run.
So what we end up returning is, yeah,
like a promise that hasn't been started yet.
And so you kind of compose these.
Let's say we need to call out to a bunch of web services,
like, you know, call, get an hint from this one
and feed that into this one, so on and so forth.
So we return these IO wrappers
and we compose them together to say like,
okay, when this one's done running,
feed that value into here.
And it's very easy to compose.
And then at the end of the world,
like at the end of our request chain,
we say, okay, now run this.
And so that lets us kind of encapsulate
the dealing with the outside world
into this type that we wrap the results in.
Yeah, that makes sense.
Actually, one thing you mentioned
is a really good point.
Functional programming, because each function
is isolated, it lends itself
really nicely to parallelism.
For example, you might write a simple script.
Maybe you write a simple Python script that
does some text
transformation, and you have this
huge block of text. Maybe it's
some
comma-separated value that you pulled
out of this Excel spreadsheet you've been working on
that has thousands of rows. And you're going to do
some transformation on all of the
on each line.
If you just do Python, you could
do it. It might not take that many lines of code.
You just do a for loop for each line, do your replacement, right? But it's going to go through
each line one at a time, right? But there's no reason it has to do that. You could have one
process loading these lines from disk and then another process writing them
to disk. And both of them can be going as fast as possible.
With Python, that's going to require setting up a thread pool. It'll probably have to be
a multi-processing thread pool. You have to create all of these, spawn off all of these
tasks. You have to have a feature.
You have to do a lot of work yourself, a lot of the heavy lifting.
With a functional language, they've designed it so that they do a lot of that work for you.
So for many of these languages, and now this is starting to make its way into a lot more than just functional programming languages. But yeah, this whole future promise async await pattern,
that really came out of functional programming.
And for example, you can write something that solves a game search,
like solves a checkers game or something like that in Lisp,
and it will automatically use all of your cores.
You don't have to be fuddling around with thread pools
and all of that yourself.
Totally.
It's interesting what you're saying about how this stuff
is kind of feeding out into other languages.
Because if you think about, you know, at some point,
Python having map and filter and stuff was considered functional programming, just because that was an idea kind of feeding out. parametric morphism that originally came from Haskell and then was brought to Java.
And, you know, like lambdas obviously are quite popular now.
So I feel like there is, you know, a conveyor belt of taking these ideas and feeding them
back to other languages because there is a lot of value in them.
Yeah.
I mean, especially, I mean, a web server is a great example where
you might have one person who they, maybe they're on their phone, and they send you
a request saying, hey, get me the weather. And your service tries to return the weather,
but that person goes under a tunnel, and now they have no reception. And so you're just pinging this
person saying, hey, I have your weather, I have your weather,
come get your weather.
And if everyone else,
maybe you have 100,000 users on this site,
if they're all blocked because of that,
your website just, it's not gonna be functional, right?
I know, pun intended.
But that's where, again, a functional language
is really shying because that actually
can be really tricky to get right.
Even if you have eight threads, now you can support eight people.
If eight people lose reception, your website goes down.
And if your website has thousands and thousands and thousands of people,
that's not unreasonable.
Functional languages are really, really good at having these executors that sort of manage a lot of this.
So if there's a function that's waiting on some hardware device or some IO, that's okay.
The language, the engine underneath the language knows to just put that one on hold, pick up a different one.
And that's the kind of thing that can be really, really difficult to get right.
So as we talk about a lot of these concepts making their way into other languages, keep
in mind that there's a lot of advanced techniques in the functional languages that still make
them really, really good for much better at doing these kind of tasks.
Yeah, totally. Um, there was an example I remember from, from when I was learning this, um, that, that kind of made a lot of sense
to me where somebody had like this, okay, here's like a, a service that, that processes, uh, coffee,
like you're buying coffee. So it takes in, takes in um like a a credit card and then
you know it returns like some you know something representing a cup of coffee and then you know in
the body of this it goes out and charges your credit card it seems like a reasonable solution
right and then so but obviously it doesn't kind of of meet this functional aspect we were talking about. So if you could transform it, so you take in the credit card and you return both a coffee cup and then something that kind of encapsulates this effect.
So let's say it's just like a data structure that says, you know, charge this card so much money.
And then somewhere, you know, obviously you have to actually have to apply this charge.
But the interesting thing is if you start thinking about adapting this, now what happens if like, you know, we say you make the one solution, I make the other.
And then, you know, requests come in like we want to buy, you know, a whole bunch of coffees, like we're going to buy five coffees.
In the system where we're going out and like like, charging the card for every coffee that comes in, I mean, that's not what people expect when they buy a coffee. Where the system that kind of returns these charge objects, you could imagine just a process that kind of merges them before it actually, you know, sends off the request and is able to like batch the effects, right?
So this idea of making the effects,
making the side effects you're going to do in the world,
like an explicit thing in the domain of your software.
I mean, I think that's one of the kind of ideas, if that makes any sense.
Yeah, totally.
I mean, I think this will also be revealed when people try to test things.
So let's say you have some service that configures your router and you try to test it.
So if you have a unit test,
which literally is going to go and configure your router
and you're going to run it hundreds of times
and people will be running it with bugs,
well, you're going to have a really bad router, right? That's a scary network to be on. So what you really want is to mock that out.
And by not allowing, let's say, globals, for example, or by discouraging globals,
you kind of force people to say, okay, this global router object that points to some driver that i got from cisco
um you know i can't i can't rely on that always being there or i can't rely on globals at all
let's say so maybe the first step is let's pass that in and well as soon as i pass it in now i
could pass in something else as long as it has the same signature and that's kind of how people can,
that's sort of how, I guess,
well-tested or professional software works.
Yeah.
What about in terms of typing?
So a lot of the early functional languages weren't typed.
I mean, I'm thinking Lisp.
I don't think Scheme is typed.
They're all weakly typed.
Now Scala is strongly typed. They have all weakly typed. Now Scala is, you know, strongly typed. They have the type
inference engine. Do you feel like there's, you know, what sort of side of the coin are you on?
I'm definitely on the side of types. And when I think about the value that I get out of this
proposition, I was saying earlier, like, you know, a function takes some inputs and gets some outputs.
A lot of the value I get is that the types kind of constrain what those inputs and outputs are.
So I think types are super powerful.
And, like, I think that functional programming in Scala, in Haskell, in, you know, more researchy languages, or two languages um pushing the type system to be able to better encode um the constraints of
what you're doing is is like a huge win in terms of software maintenance so yeah sorry go ahead
oh i just i definitely agree yeah i mean i've been burned so many times by weekly type languages that yeah i'm kind of done with that yeah and like um if you look at like scala or
let's say kotlin or even rust or swift like one thing you're seeing is kind of using uh like a
result type or an option type or something rather than like a null pointer um and like that so that
is another idea that's kind of you know moving out into the ether
of other languages from functional programming and just that thing is so so valuable right just
to say like hey you're not going to get a null pointer here you have to explicitly handle like
if this is you know possible that this value is not defined that's an explicit thing you need to
handle yeah i think i agree with you. It's so, so useful.
There was an issue the other day I saw at work where there's basically a function
that was meant to return some information
and it didn't support null.
And so we ended up getting a crash at some point
saying that someone tried to pass in a null.
And it turned out that there were some circumstances
where that object that we were returning,
it couldn't be retrieved.
So I mean, think about like a double delete scenario
where two people are trying to look up an item
and delete it at exactly the same time.
And the second process that arrives
goes to get the item to delete it and it's not there
but because we explicitly
banned nulls in this particular function
we got an error whereas
in other languages I mean at worst
you return the null
you don't think it's going to be null
and then you start using it
and then you're lucky if the program crashes
like much further down the line. I mean,
that's the best case scenario. It could even get worse than that. You just get corruption and
things like that. Yeah, so I think a lot of that stuff, and as you said earlier, it is making its
way. Like now with C++ 17, there's the optional. Optional is not part of the language so you could do optional foo equals bar and then
by default bar is null
but yeah there isn't support
for
there isn't support yet for
I wonder if there's a way to, Patrick might
know this, if there's a way in C++
to just
blow up, I guess you
could have an optional
where if you tried to, actually I guess optional have an optional where if you tried to...
Actually, I guess optional will do that.
If you try to access it,
it will kind of blow up.
So in the new C++ one,
if you access an optional
where the value is missing,
it throws an exception by default.
But there are ways...
You're supposed to check it
before you do that
or say, give me this value
or this default.
Yeah.
So this is a common pattern
like you'll see the same thing in scala or haskell or swift i assume um and i think that go ahead oh
i was just gonna say do you feel actually you finish your thought because i have a kind of
tangent so so i think like it so this is a great idea um and it ties in with kind of algebraic data types, which some languages are starting to get, and generally, you know, FP languages have always had.
But you can push these type ideas even further, right?
Like the phrase that I think comes from like OCaml land is like, make illegal states unrepresentable. Unrepresentable? Yeah,
let's say it that way. Okay. And so to use the type system so that, you know, you can't,
like that you could enforce invariance in your code using the type system. And having richer
types allows you to do this more easily. Can you give an example?
Is it sort of like saying you can't do three plus dog or something like that?
Is that, is that where you're going with this?
So that's a super, uh, simple one.
But so, um, if you have, um, some types, if you have, um, if you have a, a some type,
which is like a type that can be one of several values, right?
So in Scala, I would have like,
let's say I have like a sealed trait called animals,
and then I have a dog cat and parakeet or something, right?
And then somewhere else,
I have some code that does some pattern matching
and pulls those apart and handles each case. And then if I add a new value called goat or something, the compiler
will tell me, hey, you have not handled this case. This type has four possible values and
you are not handling that case.
Oh, I've seen that. Yeah, you're talking about the case classes classes is that the right word the case classes
yeah and so I think this concept of like so that that's like totality checking and some
languages take it much further but so when you're when you're writing that actually I think that
I'm trying to think of another example uh maybe
i'll maybe i'll think of one but yeah using the type system to kind of uh make it more apparent
when you are doing something wrong i guess is kind of the concept uh hey jason not to interrupt you
but before you go off on that tangent uh do you want to take a minute to tell people about o'reilly
os con oh that's right yeah Yeah, OSCon is coming up.
There's going to be a bunch of superstars there that you can listen to. They're going to talk
about actually a lot more than open source software is going to be there. There's going
to be blockchain. There's going to be AI. There's going to be cloud computing, distributed computing,
be a bunch of different talks from people all over the world you can go to oscon.com
slash pt for programming throwdown if you go there you can uh you'll get a special deal which uh
which is which is really cool um definitely check it out there's going to be a lot of really
interesting people do you know who else is signed up to uh speak so i actually would advise people
to just go look at the the website because there a ton of people. But I know that there's Holden Crew from Google, Rupa Deshir from CodeChicks,
Julian Simon from AWS, Allison McCauley from Unblocked Future. I mean, the list is really
big. Like I was starting to like, I'm going to read. Oh, wait, I'm not going to read all these
people. There are a ton of talks. So actually, I've never been to a conference where I know we
were talking about this last episode. And, you know, you were talking about it about what it is kind of like to go to a
conference. And I feel like going and talking to my boss about trying to be able to attend one,
because I think it'd be really cool to be surrounded by people talking about the kinds
of things I'm super interested in. Yeah, I mean, also, one really interesting thing that this
conference is doing is pretty unique is they have sort of speed networking. They have book signings. They give
you a really good opportunity to meet other people. I've been to conferences in the past where
it's just very, very technical. And it was designed for you to go. It's designed for
one-way communication, right? For you to go and listen to some talks. But this is really designed for you to interact and meet other professionals, which is really cool.
So definitely check it out.
You can get 25% off your pass if you use the code PT25.
I believe if you use the link, oscon.com slash PTt. You'll also get the discount,
but put the code in just in case.
And yeah, hope to see you there.
Yeah, so with all of these languages,
you know, adopting a lot of these principles
from functional programming,
where do you see the whole ecosystem going?
Like, do you see some of these languages
sort of collapsing together? Or do you see there of these languages sort of collapsing together?
Or do you see there's maybe going to be, you know, sort of an explosion of new ideas?
You know, I always kind of wonder if there be some type of contraction, because a lot
of the features will just, you know, things will just become homogeneous over time.
Yeah, I don't know.
I don't see it becoming more homogeneous like i only see
it becoming more heterogeneous i guess like uh just um like the the number of people developing
software continues to grow and like i don't know if this has to do with with functional programming
at all but like as you were saying before like if you're writing a service that that other people
are calling and some sort of grander architecture, you could write it in whatever language you want as long as you agree on the protocol.
So in some ways, we're in the Cambrian explosion of languages.
And I mean, I don't see that going away.
Certainly, the table stakes are higher for a new programming language, right?
Like you can't just write like a compiler.
You know, people expect package managers
and they expect like code linters.
That's a really good point.
Yeah.
Is there, I guess Scala has SBT, right?
For the package management?
Yes, yeah.
Yeah, there's still not a good...
Patrick, you can correct me if I'm wrong here,
but I don't think there's a good package manager for C++.
I know there's Hunter, but it's not even that popular.
There are a few, but they don't...
I've never found one that had enough critical mass of packages to be useful.
Yep, exactly.
There's Conan.
There's actually one from microsoft it's i think
it's like vc i don't remember but but um yeah you're right none of them um can really get
everyone on board i mean it seems like i can understand i mean it sounds incredibly difficult
i think like maybe you guys uh disagree or something but like so c++ just existed before the idea that like languages
should have should have a package manager um like was an important idea right and i think that
there's these stops along the road right like i think go kind of put down its feet on like having
a way to format your code easily and that like languages you know after go are all going to have
that like it's such a good
idea but but you know languages before that people are too busy fighting and their pr is about whether
you should format it this way or that way yeah that's right yep yeah i wonder uh um i really
wonder what's going to happen i do think that okay so to your point with Docker, with services, service-oriented architecture, that really gives people flexibility to write any language they want.
But I feel like the system is inherently winner-take-all as well.
And again, I think there's always going to be a lot of languages i just wonder whether the distribution
concentration will just you know favor a few languages like i think you know python you know
we do mostly python at where i work now um you know we use the typing module and all of that
um but yeah i mean there's definitely better languages um but i feel like there's this sort of winner take all effect um although
although to to sort of playdell's advocate against that um tensorflow recently added support for
swift and so that i think is a game changer for a lot of people um you know doing machine learning
and people in ai yeah um i had on my podcast uh, Brian Cantrell, and he did this great presentation,
and we talked about it about software values, I think it was called. So he was a big proponent
of like the Node.js ecosystem and had kind of a falling out with them. And he kind of thought
about this a lot and decided that like like what matters with programming languages is sort of
like where
they put their values and that it leads
to like a different system so like
Node.js kind of put a lot of
importance on just being accessible
like people being able to pick it up
and I think when he wanted some
more you know thought that there should be some
more complex features that would build more
robust software then they were like well that, that would be great, but that would
take away from accessibility, right?
And I work on Scala, which has a reputation for being very complex.
And I think Rust also has and Haskell.
So like, I feel like that's the decision space, like as a language, right?
Do you want to be like, do you favor this being an easy
language for people to take up do you favor that this is language that's that's more reliable or
more secure i mean performance is probably another um aspect but there's all these values right and
i think languages kind of pick and choose uh where they fall like c++ obviously has some very specific
you know performance and memory usage constraints on it that will
be more important than anything else.
Yeah, that makes sense.
So in the functional programming landscape, is there sort of a Pareto front there?
Like, are there reasons to use Haskell versus Scala that involve, I guess, performance?
Or is there some speciality that Haskell is particularly good at?
Yeah, so one thing that is interesting about Haskell is that it is lazy.
It has a lazy evaluation model.
And I don't know any other languages that
have that so besides all its its functional aspects it has this lazy aspect which um can
can be challenging but has uh benefits in certain cases scala i think is great um when you want to
use the jvm um because like you're not going to run into like hey
like I literally had this problem with Haskell before where I needed to interact with this like
soap web service and they're like yeah don't do that like that was there where if you're in in
Java like if you're on the JVM that's never going to be a problem yeah it's just so much so many
billions of lines of code that have
been written yeah i don't know if that answers your question though yeah that makes sense yeah
i think um yeah the lazy evaluation just to kind of give people more depth on that um because
actually it's supported in in um it's it's not it's not part of python by any means but if you're
using tensorflow or pytorch or any of these uh g means, but if you're using TensorFlow or PyTorch
or any of these GPU tensor processing libraries,
they're doing lazy evaluation.
And what that means is,
imagine you have a program
that it reads a number from the command line,
it adds four, it doubles it,
and then it returns it, right?
So it prints it to the screen, let's say.
So when you do the add four and the double,
that doesn't really change.
I mean, it changes some memory on your computer,
but you don't really notice anything
until you do something with that number, like print it.
So what a program could do is it could just keep
kind of like a ledger of what you said it should do.
So you said, oh, you want to, I forgot what I said.
I think add four.
You want to add four?
Okay, I'll make a note of that.
You want to double this number?
Okay, I'll make a note of that.
And then when you go to print it to the screen, then it goes back through its ledger.
And it says, okay, what operations do I need to do?
And so, you know,
this is a very simple example, but imagine if you did that operation to two numbers and only printed one of them. Well, then it doesn't have to do that operation on the other number, which is just going
to get thrown away. It only has to do half of the work. That's a big reason to use ledgers is the pruning but by far the biggest reason is
that there's a lot of latency
especially if you're doing anything on the GPU
you have to take information that's on your motherboard
and you have to send it over to this PCI card
and that takes time
so you can send a ton of information
but it just takes time to get there.
And so by batching up all of these commands, you can send, you know, 100 commands instead of one
command. And even though there might be 100 times as many things to do, again, it's a latency issue,
not a bandwidth issue. So you get a huge speed up by doing that and haskell has that
has that basically baked into the language yeah and like so scala has laziness as well and like a
uh call by name is what they call it but it's not the the default so it is a very powerful paradigm
as you're saying um having it as the default um, I think that's confusing for people who aren't familiar
with it. That is not, you expect a program to work by starting with the first line and then
executing through the bottom. Whereas you're describing in a lazy world, it's kind of like,
it goes all the way to the bottom, building up its computation and then kind of runs it by
backtracking through what it needs to do.
Yep. Yep. And so a lot of these languages or platforms will have sort of a immediate mode
where, for example, let's say you're developing and you need to know the value. Maybe you have
a variable that you're just stepping through with the debugger, but you're not actually even using
it. You still need to know kind of at every line of the code what that value is.
Maybe just you have all this computation and at the end you get not a number, right?
That's really hard to debug.
So with immediate mode, you can kind of step through and say, oh, this is the exact line
where things kind of went south.
So it's totally possible.
And so in a way, you kind of get the best of both worlds. So it's totally possible.
And so in a way, you kind of get the best of both worlds. You get this immediate mode when you need it,
which is a little slower.
Think of it as sort of features,
which we didn't talk about yet, but we get to,
that are resolved right away.
And then you also have this lazy mode,
which is much faster.
Yeah, and I think from like a theoretical cs
perspective like the lazy evaluation mode will always be at worst take as much time as the eager
mode um because it's you know it can but it can be faster because steps could be deemed unnecessary
but um it can have a tremendous memory overhead.
Like if you're in Haskell and you want to, you know, maybe they would say just don't do this,
but let's say that you're like summing a whole bunch of numbers, but because of the way you did
it, it is following kind of the default lazy style and you're passing around that result number.
But the result number, in fact, it's not a memory location of an int. It's actually a giant computation of like add one plus two plus three plus four. So the calculations will end up being the same. But until that's evaluated, you know, they have these kind of space leaks where you end up holding on to a whole bunch of memory without really meaning to yeah that's a that's a really really good point um just in
general these higher order languages um will will have sort of traps so i think of it more like uh
you can think of it as like using a machete or using uh you know like a chainsaw right like the
chainsaw can do a lot more it could could be really quick, but also you kind
of have to develop some more skill to use it. And I think that's, it's a good way to sort of learn
is to dive in there. You write this program and you realize, oh, why is this taking, you know,
an hour to run? And then there's, you know, there's a bunch of really good tooling for all
of these languages to step through and say, oh, i see why it's happening because i'm building this
huge computation graph of of uh all of this mathematics i'm applying when really i should
at some point um i just realize all of that computation i think they call that checkpointing
should checkpoint the computation so that it collapses that whole call graph
and then you can start again.
Yeah, and what I'm describing is probably like a very much a beginner mistake
to not realize that you're chaining around this computation.
Yeah, that makes sense.
Yeah.
What about...
Oh, so by the way, you asked me like,
hey, when should you choose which functional programming
language? So I'm going to say, you know, always choose Scala because that's my favorite.
But I think in practicality, like, you know, a language like Haskell or something
is a great place to learn about all these FP concepts. But if you need to do real world stuff,
like I said, if you need to talk to some soap thing or something, you know, the JVM is a good place to be.
Yeah, that makes sense. And if you're at a company or you're doing some software task now in a
different language, one thing everyone can take away from this podcast is to, you know, realize
how to do functional programming in that language. And so just to enumerate a lot of this,
I mean, if you're in C++, you can use Folly Future.
Actually, Patrick, you might know of other alternatives to that.
The only one I've ever used is Folly Future,
but there's probably a hundred other ones
that basically give you this async await type paradigm.
You know, if you're in Scala or Haskell or something like that,
that's very natural.
If you're in Java, there's got to be some good libraries,
but you're going to be creating a lot of objects.
So get ready for a ton of objects.
Other language?
Oh, yeah.
If you're doing anything like Node.js
or even if you're doing React or JavaScript in the browser,
definitely look at the await async libraries in Node.
I think there's RxJS in the browser.
Before we enumerate all of them,
look up like it would either either be you know reactive programming
functional programming um there's there's a way to do it in every language and depending on the
task you're trying to do it could be really powerful so um definitely you know dive into that
um and and it's something really good to understand and and types, right? If you're doing React stuff, I don't know, maybe
TypeScript or Flow or, you know, and another keyword I'd call it is like algebraic data types,
which more languages are getting support for, but is a nice way to kind of build data structures.
Yeah, that's one thing that drives me absolutely crazy about TensorFlow and PyTorch is they just have the tensor data type.
So if I have a tensor that's sometimes I've done this where I have a tensor that's I'm going to make sure I get this right.
Yeah. Yeah. OK. So I have a tensor. Let's say five by one. So it's a vector. Right.
And then I multiply by another tensor that's 5 by 1.
So what that's going to do is it's going to multiply those two vectors,
and that's going to do a dot product.
So under the hood, it's going to multiply component-wise,
add that all up, and I'll get a single number out.
So maybe I do this vector times vector,
or they're calling it tensor times tensor, or this, you know, they're calling
it tensor times tensor, and my output is three, right? But if I get the dimensions wrong, like,
let's say one of those two vectors is transposed. So now I have a five by one matrix multiplied by
one by five matrix. Well, what sensor flow is going to do is it's going to do the outer product. So my result isn't going to be 3 or 10 or 100.
It's going to be a 5 by 5 matrix.
And nothing warns you about that.
So you could just easily get blown up because sometimes we have these huge vectors and we multiply them together.
Maybe it's a million items.
And we expect them to output
a number, but what ends up happening is
it outputs this million by million matrix.
And it can't even fit that matrix.
So your graphics card blows up.
Right?
That just absolutely drives me
crazy. There is
something coming out in TensorFlow called
Named Tensors. It's not out yet, but drives me crazy they are uh there is something coming out in tensorflow called named tensors
it's not out yet but um you know i think to your point i mean it's it's moving in the direction of
sort of algebraic types so i mean i think the holy grail there is where you have unit types you can
define like you could say seconds s equals 10 microseconds and it would do the conversion automatically stuff like that
yeah uh so like a different holy grail is like if you've actually would encode the size of your
matrix into the type so i've seen this i've seen this uh done in a couple languages. So an example in the Idris programming language
is actually like he has this function
to transpose a matrix.
And the way he defines a matrix is
it's like matrix and it has two type parameters
that is like the n by n size, right?
So he has a function that takes in a matrix
that is size n by m. Maybe those are hard to say
over audio. I by j, let's say. And then it returns it like j by i, right? So by encoding that kind of
dimension into the type, you can actually understand that that is a transpose function,
like without even understanding the body of it, right?
You can see just by that that these two variables move that it's actually kind of rotating the matrix
Yeah, yeah, and if you do
You know if you multiply these vectors and you set that equal to a floating num point number then the type system could know
Okay, there's only certain multiplication,
matrix multiplication operations that can yield just one number, right?
Yeah.
And so it would catch that compile time.
Yeah.
And your example of, yeah, exactly.
Returning like instead of a float, some giant matrix.
If the type system had that information, yeah, it would be a compile time error.
You would never even send it off to run. Yep. Yep. Yeah. I, uh, I'm also a huge fan
of TypeScript. Um, the one thing, uh, it was, it was really hard to set up. Uh, but, but to be fair,
I was trying to go for the Holy grail. I did get it eventually. Uh, but what I got was what I wanted
was, um, basically the servers and TypeScript running Express.
The client was running React, also in TypeScript, and both of them support hot reloading.
So what that means is you can edit a source file, hit save, and your server changes underneath.
On the client side, every time you hit save, it refreshes the browser and it's up to date. I posted two or three months ago, I posted from Hacker Moon an article on how to do
it. It was definitely a lot of work, but it was totally worth it. I think if you're going to build
a website, that is the way to go. And as you said, you the type safety which is which is actually really important it's it
saved me multiple times yeah everybody who everybody who whom i've heard talk about move
a large js uh code base to typescript has talked about like oh there was a couple bugs that we
didn't know about that it just called out and like obviously they're not very prominent bugs
because they would have already got to them but But like, you know, if you were developing it in TypeScript,
they never would have even been there.
Yep. Yep. That's right.
And it just helps new people too,
who are looking at the code base.
It's very hard to dive into the middle of a code base
and know what's going on.
But the type system is really sort of your dictionary
that you can kind of carry with you
as you're kind of
diving through all of the code yeah i love that like you know uh maintainability when you have
a lot of types like you know we use types quite extensively in our scala code bases probably in
ways that would be unusual to people but like when you can go in and say i want to move this here
and you kind of can move it and then see what breaks and then slowly, you know, work those changes through.
As opposed to like, you know, some Ruby or Python code base where you better have good code coverage and some great reviews.
Like the differences are astounding.
So one thing before we jump, I want to jump in and talk about your podcast and other things that you're working on.
But real quick, how do you keep people from your team
from creating like crazy Scala operators?
Because I've seen in our code base some unbelievable operators.
I honestly thought they were those Animoji, you know,
those five-letter long uh you know like emojis
or they're flipping the table or something yeah how do you keep people from abusing the language
well i guess those are two different questions we haven't had the operator uh the operator problem
um maybe that has to do with personal uh tastes of on the team. I think that there was a while where that happened.
In the community of Scala,
that it was common to write custom operators for a lot of things.
And I think that maybe that's not the case anymore.
But I also think it's a case where if you get used to an operator,
then you love it.
You find it easier to understand than than a word or but but
if you're not used to it it's very confusing i feel like it's a little bit like like vim like
i use vim key bindings and intellij and uh like now that i know the bindings and everything like
it's like amazing but you know before i knew it it was like super confusing and i was like why
would anyone use this yeah right i went through the same thing uh you know being a machine learning person I know emacs because that's
that's what they taught us in in AI class but but yeah I remember the first time the professor
forced us all to use emacs what are you doing to us it's like ctrl s to search what's going on but
then over time you realize uh not taking your hands off the keyboard is pretty nice.
Yeah.
So I think that operators, like it's great that you can do operator overloading.
You should only really do it if it's something that's going to be like that.
Like you're just going to, you're not going to have to look up what it is. Like if it's going to be muscle memory for your team, like, oh yeah, of course, this
means combine two lists together and then increment everything by one.
I don't know.
Yeah, that's right.
Yeah. and then increment everything by one. I don't know. Yeah, that's right.
One thing that trips people up to is the underscore for arguments that don't matter. So just to give people some context, if you have a function and – let me make sure I get this right.
A function takes sort of, let's say, say two arguments but the first argument you're not using
you can put an underscore just to say
hey I know there's supposed to be something here but it's
irrelevant instead of putting the word
dummy or something like that
but then what can happen is you can
end up with like open paren underscore
plus underscore close paren
and people look at that and think that that's one
whole operator right
yeah which ties into your other question right like how do you like and people look at that and think that that's one whole operator, right?
Yeah, which ties into your other question, right? Like how do you, like Scala is a very flexible language
and then so how do you restrict, you know, what people do?
Because you can do more than that with underscore
because you can refer to it, right?
So you could have a function that is like bracket underscore comma underscore
bracket and then like arrow and then underscore dot one and underscore dot two like that's right
i mean uh so i think that that is a harder question right like how do you uh i mean i
think the same is probably true of c++ to an even greater extent like the language is so large you
have to kind of as a team uh reach kind of some
sort of consensus but in scala like we use linters and code formatters and kind of enforce things in
the build and that that's great like uh something like instead of arguing about code formatting like
nprs we have a config that that kind of dictates what our code formatting will look like. And if
you want to argue about it, you could just make a change to that and then argue in that PR where
it reformats everything to the new standard, which is just great at removing the diversion of arguing
about code formatting. Yeah. I mean, I remember the days of people arguing over spaces and things
like that. I mean, it was just unbelievable. And
now, I mean, even C++, every language has some type of way to automatically format. And that
takes so many of these arguments off the table. It's like, if you don't like the formatting,
you could even reformat the whole code base and then just format it back when you go to submit
your PR. I mean, if you're that into it um but but uh yeah i agree
with you i think some of the more semantic uh things are just handled in the in the peer review
so we have this we have this sort of meme we call clown town and so it comes from the simpsons but
i don't watch the simpsons so so someone will have to correct me on that. But yeah, there's basically this emoji we have of Krusty the Clown.
And so when something's getting kind of clowny, we put Krusty on it.
So if someone has a pound to find that creates a class in C++,
they get Krusty, and that's the way we sort of enforce it.
We have a bike shed emoji for when people start fighting about dumb things wait what is a bike shed i don't even know um i think it
goes back to this old story that says like you know that they were building a nuclear reactor
and they had a committee to like oversee all the plans and then the committee spent all their time
arguing about the color of the bike shed
because like the idea was that the people on the committee
didn't know anything about nuclear reactors,
but they understood bike sheds.
So they're like, that's what they focused on and argued about.
It's kind of like you're missing the,
you're focusing on the wrong thing here.
Yeah, yeah.
That's amazing.
I noticed that, well, you know, it takes a certain personality to invent an entire framework or library or even programming language.
And so you have to be sufficiently dissatisfied with the status quo, right?
And so when you get a lot of programming language inventors or platform inventors together,
you end up with a lot of contrarian opinions.
And yeah, I think I need to borrow that bike shed emoji.
Yeah, it's true.
You can have too many divas or I don't know what the right word is.
Yeah.
So tell us about your podcast.
So it's co-recursive.
Do you, is it purely recursive programming
or is it just, is it more general?
What's the sort of topic?
So it is not purely about recursion.
So the show is an interview format.
And so it is a software development podcast.
And if I'm curious about a subject, say, similar to this episode,
or if I want to know about TensorFlow or some new programming language,
I find an expert in that area and bring them on
and kind of have them explain that area to me.
And I ask questions and I'm hopefully not afraid to say,
like, I don't understand.
Could you explain that again? And so that is the format. It's kind of a deep dive onto a technical area,
an interview at a time. There's been a lot of shows on areas of functional programming,
shows on building your own programming language, shows on Rust, incident response, kind of a wide swath of topics. But I just picked the
name because, well, a co-recursive function is something that kind of produces a stream of
values. So it's kind of like a pun in that I'm producing a stream of episodes. But really,
it's just the name that's distinctive distinctive so what inspired you to get into
podcasting um so i was uh listening to a lot of tech podcasts and i i thought that there was
certain topics that i would love to have covered that i didn't really see being covered and
originally i reached out to this podcast se daily to see if he would cover some of these topics and
he said well why don't you try like just doing guest hosting for the show and uh i did that once
or twice and then i just found that it's a lot of fun um like i like to be able to talk to people
about software and so uh yeah can't can't stop now oh that's awesome i'll have to make you a trade
and i think i can
come on your show if you want to talk about any machine learning stuff that would be awesome
cool and can people catch you on uh like what sort of social media are you uh you know most
prevalent on yeah so definitely you know check out the podcast at co-recursive.com uh if you
you know google adam gordon bell you'll find me i'm on
twitter at at adam gordon bell and also at co-recursive and uh yeah cool so if people want
to reach out to you they uh do you support uh dms on twitter or should they email you through the
website how can people get a hold of you yeah you can You can DM me through Twitter. You can email me, uh, Adam at co-recursive.com and, uh, yeah, check out the podcast. I think it's super interesting.
If you liked this episode, uh, and you need more podcasts, I think it's probably a good fit.
Cool. Yeah. I mean, we, uh, we get a lot of people saying, Hey, why don't you do more episodes?
Um, um, but, uh, but you know, I think that there's, there's a lot of really good producers
out there creating a lot of great content. And, and Patrick and I also have a lot of kids. So
one episode a month. And, and, and yeah, if you're interested in knowing more about
really a lot of these topics that, you know, that we're all interested in, but especially recursion,
functional programming, things like that.
Adam does this literally every day.
He's very passionate about it.
You should check out his podcast
and hit him up on Twitter.
All right.
So thanks a lot for coming on the show, Adam.
I really appreciate it.
This is an awesome episode.
I think we really dove deep on functional programming
if people still have questions
don't hesitate to email us you can also ping
Adam you can email both of us
but I think we will hopefully we cleared
up you know a lot of the mystery
around functional programming because it is something
that's really difficult to dive into
yeah this was a lot of fun thank you
so much.
The intro music is Axo by BinarPilot.
Programming Throwdown is distributed under a Creative Commons Attribution ShareAlike 2.0 license. You're free to share, copy, distribute, transmit the work, to remix, adapt the work,
but you must provide attribution to Patrick and I
and sharealike in kind.