One of the nice things about the Python programming language is it's at least three programming paradigms in one.
There's the procedural style, the object-oriented style, and the functional style of programming.
This week, you'll meet Evan Hubinger, who is taking Python's functional programming style and turning it to 11.
We are talking about Coconut, a full functional programming language that is a proper superset of Python itself.
This is Talk Python, episode 117, recorded May 22, 2017.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter, where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm.
And follow the show on Twitter via at Talk Python.
This episode is brought to you by Rollbar and Hired.
Thank them both for supporting the show.
Check them out at Rollbar and at Hired underscore HQ on Twitter and tell them thank you.
Before we jump into the main part of the show, I want to let you know that we're adding a couple of new courses over at Talk Python Training.
Within the next few weeks, we'll be releasing RESTful HTTP services with Pyramid and Python, including a SQLAlchemy data-driven backend, and another course, MongoDB for Python developers.
If you're interested in either of these, be sure to create a free account over at training.talkpython.fm to get notified.
Evan, welcome to Talk Python.
Thank you. Thank you for having me.
Oh, it's an honor to have you. I'm really excited.
You've got this really cool project that I think is doing some interesting stuff in the Python space.
And so I'm pretty excited to share this new functional superset of a language that you've created.
But of course, before we get into the details with Coconut, let's talk about your story.
How did you get into programming in Python?
So I started programming actually as a sort of summer camp thing between middle school and high school.
It was not a very well-taught summer camp, actually.
It was really just, we're going to throw some Python at you.
I took a look at it, and I sort of experimented with it, and it was interesting.
What really got me excited about it was just the things that I started to be able to do once I just was exposed to it,
and then started learning about Python online, going through the documentation, and building up.
I started writing text games and worked my way up to more complicated mathematical stuff,
follow along what I was learning in school.
And as I went through, I sort of worked my way through the various different things in Python,
working my way to know the language better and better,
all from this start just as, what is this thing?
This thing that actually lets you take a computer and give it commands and actually output something that's interesting, useful, and powerful.
And so that was my beginning, my introduction, the way that I got started.
That's cool.
And the first language was Python that you learned?
My first language was Python.
Yeah.
And I used Python pretty exclusively for many years after that.
The second language that I really got into after that was Haskell.
Okay.
Yeah.
Haskell is definitely one of the more popular functional programming languages, right?
And so did that kind of blow your mind?
You're like, whoa, Haskell's different.
Absolutely.
Yeah.
So I, at that point, had been pretty used to Python.
That was sort of two years after I had originally learned about Python.
And since that time in doing a lot of Python, like I was saying,
Haskell was this new experience.
This experience of there's all these new concepts, all these new features,
all these new powerful things I'd never seen before.
I was blown away by how powerful pattern matching was.
I was blown away by how powerful all of the sorts of different constructs that I had available to me,
the different things that I could do in Haskell that I had never seen before.
And one of the first things, the sort of mythical origin story of sorts was one of the first things I did
when I tried to learn Haskell was I went back and I tried to implement it and like do all of those things in Python.
And of course that wasn't, that didn't go as well as I was hoping.
And that was the sort of basis and jumping off point for what I would later do.
That's really cool.
Is that the thing you called Rabbit?
Yes.
So originally, so the very first programming language that I wrote was Rabbit.
That was a, just a sort of project that I was making.
I was like, I'm going to take all of these cool Haskell features that I think are awesome,
all of these new things that I'm learning, and I'm going to put them in Python.
I'm going to write an interpreter on top of Python that, of course, that's a terrible idea for what should have been obvious reasons.
But how long can it take, like a week?
But yeah, so I wrote that.
It was, it was, it was fun.
It was a cool, interesting project.
Would not recommend trying to write code in Rabbit.
But it was a big learning experience for sure.
And a lot of the lessons that I learned in that process, I would later apply to Google.
Yeah, that's really cool.
And Rabbit is actually on GitHub.
So I'll put it in the show notes.
And if people want to check out your first attempt, they can do that, right?
Yes.
That's on my GitHub.
Nice.
All right.
So what do you do day to day?
You're still in college, right?
Yes.
So I'm a student at Harvey Mudd.
I'm a rising junior.
And for people listening to other parts of the world, where's Harvey Mudd?
Harvey Mudd is in Claremont, which is a suburb of LA in California.
Yeah.
Excellent.
Okay.
And then you also did some intern work at some pretty interesting companies, right?
Yeah.
So I am currently an intern at Google.
Last summer, I interned at Yelp.
And before that, I was an intern at Ripple.
Oh, that sounds...
That's pretty awesome, man.
What do you think of that experience?
It's been a blast.
I've really liked all of the companies that I've worked for.
I've done a lot of really interesting things as part of those jobs.
And Yelp, of course, that was really exciting last year because that was all in Python.
Oh, yeah.
Nice.
So you're a math CS grad, right?
That's correct.
Yes, I'm a math CS major.
I see.
Nice.
So, yeah, I also studied math, not so much CS.
Like I said, it's a bit of a minor type thing.
It wasn't called that, but more or less.
And so how do you feel like that's prepared you for this, for these internships and some
of these experiences?
Obviously, the computer science portion of it is there.
But the math thing, it really is also there as well.
I know that in my work at Yelp, there were points where I used graph theory, points where I used
number theory.
So the stuff really does come up where you want to have that background to be able to fall back
on to help you handle weird, interesting, challenging problems.
Right.
More in the algorithmic side.
Yeah, nice.
I also feel like math, if you get really into math, like advanced math proofs and real analysis
and things like that, it teaches you how to think and solve problems.
And it doesn't really matter the rules around it.
The programming rules are programming rules, right?
I think it's pretty good for foundation.
Yeah, I totally agree with that.
Awesome.
So you've had this Pascal experience.
And of course, there's a number of different functional programming languages.
Why don't we talk a little bit about like, what is functional programming?
I mean, it's not just using functions, right?
It's entirely different than that, isn't it?
Yeah.
So the sort of textbook classic definition of functional programming is that it's all
about pure functions.
It's all about immutable data structures.
And all of that is true.
Functional programming does involve pure functions.
It does involve mutable data structures.
But one of the things I think a lot of people get frustrated by with that definition is that
it's sort of exclusive.
It says what functional programming is not.
It isn't about mutability.
And it isn't about functions with side effects.
But it doesn't say what functional programming is.
And what functional programming is, is really those are the parts that Coconut is really
trying to nail down.
Because Coconut isn't a pure functional programming language.
But what it brings to the table, and what functional programming brings to the table,
and what Coconut brings to the table with it, is the way that you work with those pure
functions and those immutable data structures, having them, the things that that lets you do.
It lets you have things like higher order functions.
So you can take paradigm standard practices and turn them into functions that you can then apply
in general concepts.
It lets you have pattern matching.
It lets you, instead of having to explicitly define how you're going to match or take a
look at a particular incoming data type, it lets you just define a general pattern for
what the data type looks like and how it gets deconstructed.
Right.
Maybe the best way to conceptualize that is it's a little bit like function overloading,
but way more general, right?
Yeah.
That's definitely a good way to think about it.
Because when you're overloading a function, I guess, in like C or C++, you're doing it
based on just types.
And pattern matching is sort of, what if you could do that not just on types, but on all
sorts of different attributes of the data?
What if I could have a different function call for when it was an empty list versus when
it wasn't an empty list?
And that's, yeah, that's one of the big things that the pattern matching list you do.
Awesome.
Yeah.
We'll dig into that.
Yeah.
And you also have lazy evaluation.
There's some other follow-ons or corollaries from this that are very, I think one of the
reasons driving functional programming is with this immutability and no side effects, parallelization
becomes like what they call embarrassingly parallel, right?
Where it's just like, well, you just break it into pieces and just do that, right?
Because you don't have to worry about one piece getting ahead of another, right?
Yep, exactly.
Exactly.
Parallelization becomes really trivial, really easy to do when you have your functions written,
your data structures written in a functional style.
Nice.
Nice, nice.
So give us some examples of existing functional languages.
So I mentioned Haskell.
I'm a big fan of Haskell.
I've used Haskell a lot.
But there's definitely lots of other functional languages.
On the sort of more pure side, you have languages like OCaml and Erlang, as well as Elixir.
It's a newer variant.
On the sort of middle ground, sort of half-functional, you have languages like Scala, languages like
CoffeeScript or LiveScript or JavaScript.
There's really a whole wide array of functional programming languages out there that try to bring
in some of these new powerful features and put them in different contexts.
Sure.
And if we think about Python, Python itself has some functional components, right?
We could go like full in OOP programming in Python.
We could go quite deep into the functional program.
You can, or just straight imperative code, right?
We can sort of pick some pieces up and choose a style for Python, right?
Yeah, absolutely.
I mean, that's one of the things that I love about Python.
Python really is great at being a multi-paradigm language.
You really can do all of the functional programming stuff.
You know, one of the things, of course, that I would say attest to that is that Coconut can
compile to Python and make it all work, even when you try to import it from Python.
But there's a lot of things that, while they technically work, really don't work nicely.
So when Python is designed, the sort of whole philosophy around it, the use cases that are
considered really aren't generally functional programming use cases.
You know, when the syntax is designed, when the various different use cases are considered,
it's mostly thinking about and considering object-oriented use cases.
And that's fine.
Python's a great object-oriented programming language.
But it means that a lot of the functional programming use cases will get left behind.
So you have things like Python's Lambda, which is notoriously ugly, as well as functools.partial,
which is difficult to use.
You get a lot of things that don't really...
Features you would really like to see from a functional standpoint that don't exist at all.
Features like tail call optimization or tail recursion elimination.
Features like pattern matching.
And features like immutable algebraic data types.
A lot of that stuff is missing.
Right.
The very dynamic nature of Python does make it a little bit hard to have immutable data types,
for sure.
And yeah, its primary thing is not in its functional style.
I would say whatever it is, maybe it's OOP, maybe it's not quite, maybe it's something slightly
different.
But functional is not its primary focus.
Do you think that the adoption of things like Scheme and Lisp and Haskell and whatnot is somewhat
limited by its pureness?
I would say that's definitely true.
Because it really is much more difficult to try to learn a pure functional programming language
than it is to try to get...
Especially if you're coming from an imperative, non-functional background.
Than it is to try to go with a language that is partially functional.
Haskell is great, but getting started with Haskell isn't easy.
There's a lot to learn.
There's a lot of new concepts that you may not be familiar with, even if you've programmed
for a long time in other programming languages.
And so that really does create a barrier to entry.
I guess so.
It definitely seems like it would be a challenge to me.
So you decided to add one more language to this list of this spectrum of functional programming
languages.
Yeah.
So what's this project called Coconut?
Yes.
So that's true.
So Coconut is a functional programming language that compiles to Python.
So some of the basic design decisions of Coconut.
Coconut syntax is a strict superset of Python 3 syntax.
So Coconut takes Python 3 and adds on top of that new features for functional programming.
That includes things like algebraic data types, tail call optimization, pattern matching.
And then Coconut takes all of that and compiles it to universal version independent Python.
Yeah, the version independent part is pretty awesome.
Well, and it's version independent in certain ways, right?
Like the syntax that you write into your Coco files, that's Python 3, right?
Exactly.
So Coconut syntax is based on Python 3.
It's a strict superset of Python 3.
But then that gets compiled to Python code that is compatible with 2.6, 2.7, 3.2, and above.
Right.
So the execution engine can be either Python 2 or Python 3, but you input Python 3 or pure
Coconut, right?
Yes, that's exactly correct.
Coconut code you input is a strict superset of Python 3.
But the compiled output is universal or you can specifically target one Python version or
another.
Okay.
There are some cases where you are forced to target a Python version.
One example of this is if you wanted to do something like 3.5 matrix multiplication.
There's no way to backport that to Python 2.
And so you're going to have to pass a flag that tells the compiler, I only care about 3.5.
Right.
Okay.
Yeah.
It's really interesting the way it works.
I mean, the analogies that come to mind are like TypeScript, right?
TypeScript is a superset of JavaScript, compiles of pure JavaScript.
C++ on top of C, right?
Not so much things like CoffeeScript where it's entirely a different language.
It just happens to transpile into a thing that you might know like JavaScript or something.
So I think that's going to make it much easier to adopt, right?
Like if I've got some program that's Python 3 and I want to make it more functional, I could
just put a different file extension, the .coco on it, and change it where it matters, right?
Yeah, that's exactly it.
So that was a purposeful design decision on my part from the very beginning.
One of the really core things that I, like I was saying earlier, learned from Rabbit was
I want to make sure to have a coherent story for how people are going to adopt this, why
people are going to use this, and how even just as an existing Python developer, I can make
something that is useful to you.
And one of the ways, one of the really fundamental ways that I try to achieve that is via this,
we're going to make the whole syntax a superset of Python 3.
That way, you already know, if you know Python 3, most of the core syntax of the language.
You don't have to learn anything new to be able to do things you already know how to do.
The only things that you get to learn new are new features, new things that you can add
to your repertoire.
So the point is not to relax, reduce the amount that your Python developer is capable of,
but only to expand and to allow you to be able to do new things in Coconut that you wouldn't
otherwise be able to.
That's really cool.
And I can tell you from going through the tutorial, there's some really mind-bending stuff in there
that we're going to get to.
It's pretty awesome.
So before we get into the details, why do you choose Coconut as a name?
Oh, as a name.
So that's a reference to Monty Python and the Holy Grail.
And the Knights Insane and those guys are clicking along?
Yeah, they've got the follow-behind, the Knights of the Round Table, smashing the coconuts together.
So, yep.
That's awesome.
Yeah, yeah.
If I was going to guess, that's what I thought.
But yeah, perfect, perfect.
It's really funny that a lot of people think Python is some kind of snake reference.
And of course, it's not, right?
Yeah.
Hey, everyone.
Michael here.
Let me take just a moment and thank one of our sponsors who makes this show possible.
This portion of Talk Python to Me has been brought to you by Rollbar.
One of the frustrating things about being a developer is dealing with errors.
Ah, relying on users to report errors, digging through log files, trying to debug them, or a million alerts just flooding your inbox and ruining your day.
With Rollbar's full-stack error monitoring, you get the context, insight, and control you need to find and fix bugs faster.
Adding the Rollbar Python SDK is just as easy as pip install Rollbar.
You can start tracking production errors and deployments in eight minutes or less.
Rollbar works with all the major languages and frameworks, including the Python ones like Django, Flask, Pyramid, as well as Ruby, .NET, Node, iOS, and Android.
You can integrate Rollbar into your existing workflow, send error alerts to Slack or HipChat, or automatically create new JIRA issues, pivotal tracker issues, and a lot more.
They have a special offer for Talk Python to Me listeners.
Visit talkpython.fm/rollbar, sign up, and get the bootstrap plan free for 90 days.
That's 100,000 errors tracked for free.
But, you know, just between you and me, I hope you don't encounter that many errors.
Give Rollbar a try today.
Just go to talkpython.fm/rollbar.
Yeah, so you covered some of the reasons why you built it, but, like, maybe give us some of the technical underpinnings of, like, why do we need this new language instead of just different PEP practices or whatever to work in this way?
Sure.
So, I think Coconut really does add a lot of very fundamental changes to Python syntax.
So, it's very hard to do a lot of that stuff via just, like, the PEP process.
I don't even think that that would necessarily be a good thing if sometime along the road all of that, all of Coconut syntax is implemented in Python.
It really is trying to be a separate language because it adds a lot of new stuff on top of Python that is specifically for being able to do a lot of these more advanced functional things to add to some of the more basic things that you can do in Python.
As well, I would say that as far as, like, why use Python, why get into it, the more technical underpinnings as well.
First, Coconut really is built to be useful to existing Python programmers.
You should be able to just pick it up, write a Coconut file, and immediately, like, as you work your way through the tutorial, as you work with the documentation, see new things that you can just add in to your existing knowledge of Python just to make your code more powerful, to make it so that you have new access to new features, as well as make the version compatibility story really easy for you.
Yeah, and I really like the fact that you take one input language or variation, Python 3, but then it becomes execution independent.
Yeah, exactly.
One of the really nice things about compiling to Python source code is that it really is truly independent.
You can run Python 3 even without adding any new Coconut features, or if you do add new Coconut features, run it through Coconut, get a compiled source that, because it's still Python, you can even run on PyPy, you can run on Jython or IronPy.
You don't even need to, like, if you compile the CPython bytecode, for example, then it'd be sort of very restricted, but it really is just pure Python, and so wherever you want to be able to use Coconut constructs, you can.
Yeah, that's cool. So right now the compiler, or transpiler, or whatever you want to think of it as, takes Cocoa syntax and compiles it to Python syntax that is very careful to work on both versions of the language.
Is there a chance that you could change that compiler, extend it, make it compiler to things like, could I compile it to JavaScript? Could I compile it to .NET Intermediate Language, or Java file, Java bytecode, or things like this?
There are no plans to do something like that right now. That would be a pretty massive undertaking.
But certainly possible, I suppose, sometime very far down the road, I could see Coconut going that direction.
I'm not proposing that it should, I was just kind of curious what your thoughts on that were.
I think that for a lot of that stuff, there are a lot of utilities that already exist for taking Python code and making it available in other frameworks and other places.
And Coconut can run right on top of those things, because it just produces Python source code.
Right, so you really want to just stay focused on enhancing the functional programming story within the Python space purely.
Right. Coconut has a pretty singular mission that is really focused on, I'm going to make Coconut be able to allow you to do functional programming really well in Python.
You don't have to deal with any of the weird syntax ugliness, any of the missing features.
Everything's going to work, you're going to be able to just take all of these powerful functional programming features and just run it in Python.
Nice.
So, what if I don't know functional programming, right?
Maybe I'm self-taught and I've learned Python and whatever.
Should I bother to learn or play with Coconut?
What do you think?
So, I mean, I would simply definitely say yes.
My argument would actually be that Coconut's a really nice way to learn functional programming,
because it means that you can start with everything you know about Python already being applicable.
So, you don't have to, like if you try to learn functional programming through Haskell, for example,
you have to rebuild up all of that knowledge about programming in general
and all of the different ways to perform all of the different operations.
Whereas with Coconut, all of that basic syntax is just Python.
And it's only building functional stuff on top of that that you have to learn.
And so, I think that trying to learn Coconut really is a good way to start getting into different functional programming features.
And the tutorial for Coconut is, I think, a great way to do that.
Yeah, that's really cool.
It's definitely a way to expand your mind of what's possible.
So, how do you install it?
Is there like some download I got to do?
Or what's the story?
Pip install Coconut.
That's it.
Beautiful.
It's the way it should be, right?
And then, yeah.
So, once you pip install Coconut, you have a new CLI.
You just say Coconut thing and then stuff happens, right?
Yep.
Most basic command line interface is just Coconut name of a .coco file.
And it'll compile that to a Python file.
There's, of course, more complicated stuff than that.
There's lots of command line flags and whatnot.
But the most basic syntax is just that.
Yeah, nice.
So, you basically run it through this compile step.
And then, you've got a set of Python files laying there.
And you just execute them like you would anything, right?
Any Python program.
Coconut can compile and execute if you want it to take care of both of the steps.
If you pass the minus R flag.
But it can take care of a lot of different things.
It's got a lot of different features.
But most fundamentally, it's a compiler, transpiler, whatever you want to say.
You give it Coconut code, it turns it into Python code.
Sure.
Okay.
So, one of the pieces of syntax.
Like, it's a little.
It's beyond a little.
It is hard to talk about syntax in audio format.
So, I don't want to do it too much.
But I want to touch just a little bit on a few things.
Because a little bit, I think, will give people a strong idea.
So, one of the things that's kind of annoying is if I want to take one function and pass its value to the next function and pass its return value to the next function.
I basically have to do that inside out.
The innermost.
If I want to do it in one expression, not multi-line, right?
I take the first function.
Then I wrap it.
And I call it the second function.
I take that and wrap it in another one.
And so, you don't read it normally.
You read it, like, inside out, which is not great.
So, you have this syntax in Cocoa and Coconut that says, left or right, take this and flow it to the, you know, almost like a Unix pipe sort of thing, right?
Yeah.
Pipeline operators in Coconut are borrowed from F Sharp.
They exist in a lot of other languages as well, like Elm.
But, yeah, the basic idea is it's a much more intuitive way to read and think about function calls.
It really is one of the more syntactic, sugary features.
It's not like something like pattern matching or tail call optimization that is sort of a more powerful thing behind the scenes.
But I really do think that it's a good example of a way in which just from the most basic level before you even start delving into the more complex functional programming features, it just immediately makes your code easier to read, easier to understand, easier to follow.
Because, like you were saying, that is how we more intuitively, natively think about functions is you take some value and you apply a transformation to it.
And then you get something new and then you apply another transformation to it.
And when you write it with that syntax, that's exactly the way that it looks.
And so I do really think that it does make it look nicer.
Yeah, it's pretty interesting.
Let's talk about some of the other features.
Some of them are pretty straightforward.
So you have an alternate Lambda syntax.
Yes.
Give us a sense of what that is.
And also, why did you create that?
It's not that different.
No.
So the alternate Lambda syntax is just an arrow.
It's the hyphen and then the greater than sign, which is already used in Python 3, for example, for the return type annotations.
But the basic idea and operator of these, because another programming language is you use Lambdas a lot in functional programming.
And the word Lambda is somewhat ungainly.
You don't really want to have to write it everywhere.
Of course, you still can in Coconut because it's a strict superset of Python 3.
But it gives you this new syntax that lets you work with it more nicely and make it easier to read.
Again, another one of the more syntactic sugary features.
Coconut does have a lot of nice sugar to play with.
Yeah, and there are some special cases where there's like super short versions of these Lambda expressions where they basically expand out in the arguments, right?
Like X comma Y.
Do like star.
Star in parentheses.
And then it'll like do like an expanding multiplication or something like that, right?
Yeah.
I think you're referring to a couple of different things.
It's the sort of star in parentheses.
That's a syntax that is somewhat borrowed from Haskell.
But you can get an operator function, which in Python you would have to do normally via import operator and then like operator.add or something.
You just put the operator in parentheses, which is another nice syntactic sugary thing.
As well as you can then like compose that with other functions via function composition operator.
Partially apply that via coconut's partial application operator.
And so you can work with these operator functions, work with the built-in functions to build up sort of more complex composite functions out of those in a very functional manner.
Yeah, that's really cool.
All right, let's dig into some of the things that are like farther out there, let's say.
Let's start with algebraic data types.
Those seem pretty easy to describe on air.
All right, I'll give it a shot.
So algebraic data types are fundamentally, first of all, immutable.
And so that means that they've just got, they're sort of like classes, but they've just got that one constructor at the very beginning.
You pass in the data that's going to be inside of it.
And then it's done.
You have a new data type.
Sort of like a tuple.
Yeah, to me it looks like you take the class word and you change it to data.
And then it has a sort of convention for the initialization because it can't be changed once it's initialized, right?
Yep, yep.
You change class to data and then you put the arguments to the constructor effectively, the different things that will be inside of it as instead of the like inheritance right there in the syntax.
But then there's a lot of things that are more complex, more beyond just the fact that, okay, it's an immutable data type and it's got this syntax.
Some of the things that are really cool that you can do with algebraic data types are, first of all, is pattern matching.
You can pattern match against an algebraic data type because you can say in the pattern, like, for example, let's say I have a two vector that I have defined as an algebraic data type.
And then I want to write a function that just gives me that first element.
If it's a two vector and it's got an x position and a y position.
And I can pattern match and I can say, like, two vector of x comma y in my function definitions.
Like, f of def, like, def f of two vector of x comma y.
And then it'll actually match any incoming data that is this two vector, decompose it into the components based on that pattern.
Say, okay, this value matches the pattern.
And I know from the pattern I see that there's this x and this y and I need to bind to the argument, the values inside of the algebraic data type.
And it deconstructs it into its component parts in the pattern.
And then you can take out and work with those components.
So the pattern matching component of algebraic data types is really powerful, really useful stuff.
There's some other cool stuff you can do with algebraic data types, too.
Coconut provides an fmap function that lets you map over the contents inside the algebraic data type to produce a new algebraic data type.
And there's a bunch of other stuff as well along those lines that you can do with algebraic data types that are more powerful than just, okay, it's immutable.
But it is immutable.
And that is important.
Right.
And do you use something like slots or something internally and properties to say there's a property with the name of the thing you added, but in fact, it's like a hidden field?
How do you make it immutable?
Internally, slots and named tuple are very sort of heavily relied upon.
There's some other magic that has to go on sometimes.
If you are somewhat creative with the way you define the constructor, like if you use a star, for example.
But in general, yeah, it uses named tuple and slots pretty heavily behind the scenes.
Yeah, interesting.
Maybe tell people what slots are.
I know some people know, but not everybody.
And it's kind of an under-advertised feature of classes in Python.
Not that you should use it often, but maybe you should know about it, right?
Happily, yeah.
So slots, specifically, it's dunder slots.
It's a very useful attribute that you can set on any class.
And when you set dunder slots to be some container, like I set dunder slots to be a tuple of some strings, then each of those strings, those become the only valid attributes for that class from that point.
So they're the only instance attributes that you can have.
And so for every instance that you make of that class, only the things in dunder slots are allowed to be changed, modified, reassigned, added to it.
Even in dunder init, in your own class, you can't add another thing if it isn't pre-specified in slots.
So that's a good way to get a lot of constraints for immutability.
There's also some interesting memory performance trade-offs that you get with that as well.
But let's not get sidetracked.
You talked about algebraic data types and how they support pattern matching.
Let's talk about pattern matching.
There's like a couple ways which you have this concept, which honestly I've never really done much with.
I know scheme, but that's about it for functional languages.
So tell us what pattern matching is and like how it works.
Yeah, so I sort of introduced this a little bit when I was talking about pattern matching against algebraic data type.
But in its general form, pattern matching says, I have a specific type of data that I'm interested in working on in this function.
So I want to maybe define a function specifically for dictionaries that have the form where one of the keys corresponds to a list of these parts.
And that's pretty common where you have functions that operate on specific types of data.
And pattern matching lets you define the specific type of data that you want the function to operate on.
And then it lets you deconstruct the parts of that match that you actually want to use in the body of that function.
It gives you bindings to them.
And then it also lets you, in Coconut you can use addPattern for this, lets you dispatch to multiple functions based on which patterns match.
So you can say, for this type of data that matches this pattern, I want to do this thing.
But for this other type of data that matches this pattern, I want to do this thing instead.
So pattern matching is a way to both check against your data as well as deconstruct it and make assignments to it.
Yeah, one of the things I like in the function part of it, not necessarily the sort of error handling or case matching component,
is what might have been one big function with many if statements now becomes separate functions, one for each particular case, right?
So if you have an example with a factorial and you say, literally the syntax is def factorial of zero equals one.
What the heck does that mean?
Yes, so that is valid, Coconut.
So what's happening there is you are defining a factorial function and you are saying the argument is the pattern zero.
Zero is a valid pattern and it means it matches only the very specific data that is the number zero.
And then the equals, that's just a little bit of syntactic sugar or an implicit return.
And so the last expression after an equals in a function definition is automatically returned.
Yeah, it doesn't have to be static, right?
It can be computed?
Yeah, it's just whatever the last expression is that gets returned.
Okay, cool.
Cool.
And then you have this add pattern decorator.
And you can take and create another function called factorial.
And instead of having like n for the number being passed in, you have n is int if n is greater than zero.
All right, tell us what this does.
Okay, yeah.
So also valid Coconut.
So what's going on there is you have a little slightly complex pattern.
But that's still what that is, that f is int if n greater than zero.
That's another pattern.
And that's doing a couple of things.
It's first n is int.
That's a type check.
That says I only want to match n if it's an integer.
And then the if n greater than zero, that's a guard.
And that says if my pattern matches, perform this extra check to make sure that it is greater than zero before going in it.
And say that the pattern doesn't match if that extra check at the end fails.
Yeah, that's really cool.
So basically the way you implement the factorial is you've got this one more complicated one that we just talked about.
And it just more or less calls itself, right?
And over and over with one fewer values in there.
And then eventually that pattern doesn't match.
It falls back to the one that returns one.
And that's like the degenerative case of the recursion.
And boom, you're done, right?
But there's no if statements.
You've written factorial with no if statements recursively.
Yep, that's exactly correct.
You know, that's actually, that reminds me of being confused in college.
I remember I'd kind of played around with languages like C++ and stuff.
And then I took the scheme course, a derivative of the list.
And there were a lot of things that were like, okay, we're going to implement this with no if statements.
Or, you know, the scheme itself doesn't even have like a looping construct in the language.
There's no loops.
So loops are actually done with recursion and these sorts of crazy things, right?
And I just remember, wait, do this with no if statements?
That's just kind of crazy, man.
That can't work, can it?
Right.
Well, so as a functional programming guy, that doesn't worry me as much.
Though it doesn't have to, even if it does worry you, that's not a problem in Coconut.
Because you've still got your loops there.
You've still got your if statements there.
But you get to use all of these other very powerful features that sort of can in some ways replace a lot of that as well.
And so it's, I hope, more friendly than trying to jump headfirst at the scheme.
Yeah, you know, it wasn't that it worried me so much as it just kind of blew my mind.
Like, I didn't think of programming.
Like, I had this one view of programming, which was very imperative.
And, you know, looping and ifs and whatnot and conditionals.
And then they're just like, no, there's this completely different way of writing code.
And I think that's one of the values of even if you don't ever want to use Coconut, I would encourage people to go through the tutorial.
Because it's quite involved.
And you really do.
You do get to think or, let's say, challenge your own paradigms of programming, right?
Yes, definitely.
If you functional programming really is a new, interesting, powerful paradigm.
That, if you haven't seen it before, really is nothing like what exists in a lot of other programming.
Yeah, I feel like functional programming is one of those languages that you read more and you write less.
And by that I mean you look at it and you go, okay.
I know it's two lines, but they're very deep.
I'm going to have to contemplate them for a little bit, right?
Do you find that?
Yeah, it's definitely true where it's like you can be very succinct and to the point in functional programming.
Because, like, you know, in the factorial example, it lets you define a lot of the logic without being as, without having to go through the motions of how you would actually implement it.
It lets you just say, factorial of zero is one, you figure out how to actually check to see if the value is zero and then return the right thing.
I'm going to tell you what you need to know, the most basic information, which is zero should map to one, and you can take care of the rest.
And that's sort of how functional programming works in a lot of different cases.
And it's that nature of it that is one of the things that makes it so powerful.
This portion of Talk Python to me is brought to you by Hired.
Hired is the platform for top Python developer jobs.
Create your profile and instantly get access to thousands of companies who will compete to work with you.
Take it from one of Hired's users who recently got a job and said,
I had my first offer within four days and I ended up getting eight offers in total.
I've worked with recruiters in the past, but they were pretty hit and miss.
I tried LinkedIn, but I found Hired to be the best.
I really like knowing the salary up front and privacy was also a huge seller for me.
Well, that sounds pretty awesome, doesn't it?
But wait until you hear about the signing bonus.
Everyone who accepts a job from Hired gets a $300 signing bonus.
And as Talk Python listeners, it gets even sweeter.
Use the link talkpython.fm/hired and Hired will double the signing bonus to $600.
Opportunity is knocking.
Visit talkpython.fm/hired and answer the door.
So let's talk about some of the other features.
Another one, if you haven't done a lot of functional programming, you're probably not familiar with it.
But one of the problems you can have with recursion is the call stack only has so much space on it, right?
If you need to do what would effectively be many, many, many loops or very, very deep recursion, you can end up with an error, right?
So you have a special way to solve this really cleanly.
And I'm not sure I totally understand how you determine how to solve this.
You have to tell me.
All right.
Tell me about your tail call optimization that you do.
I'll go for it.
Yeah.
So in Python, that manifests via maximum recursion depth exceeded error.
And what happens is every time Python sees a function call, it effectively creates a new stack frame.
It says, you know, pops all the existing or pushes all the existing variables onto the stack and then enters this new frame with all of these new variables.
And it does that execution.
But what that means is that every time you call a new function, you're building up more memory, you're building up more function calls, and it can get very intensive doing that a lot.
And so what Coconut does is it actually looks at every single function you write, and it says at any point, if you directly return a call to another function,
then we don't actually need to keep around the stack frame that corresponds to your current function call.
Because all of the data that is necessary to figure out what the return statement, what the actual return value of that function is going to be,
is all contained just in this other function call.
Because you've directly returned that function call.
And so whenever Coconut sees something of that form, it automatically optimizes it away to get rid of the necessity of, like, making, adding this new stack frame.
There's actually two ways in which Coconut does that for two different cases.
The most extreme, most powerful case is Taylor-Cursion elimination.
If you write a function that returns a call to itself, then you can refactor that into a wall loop, which is really nice and very fast.
If it returns a call to another function, that's a little bit slower, but you can still prevent the new stack frame from being created.
But it's a slightly more complex, more involved mechanism.
Yeah, it works really nicely.
And with the pattern matching, with the tail recursion optimization and stuff like that, one thing that I really liked was I was playing with the different versions of your implementation.
And the pure Python, or nearly pure Python version, was slower than the highly Coconut style, the ones that leverages these special features the most.
And so I thought that was pretty cool, actually.
That it's not like, well, you get this better syntax, but you're going to suffer for it.
But who cares?
You don't need that much performance anyway.
That you actually didn't, at least didn't pay a price for using it, but it seems like it actually might even be less of a price than not.
Yeah.
So in most cases, Coconut's performance is going to be very similar to Python's because, of course, it compiles to Python.
But yeah, in some cases, Coconut really can perform optimizations that will save you.
One of the biggest of those optimizations is the tail recursion elimination, tail call optimization, where it'll take a look at every function you write and just see, are you returning a call to another function directly?
Implicitly or explicitly in any way?
And if so, that gets optimized away always.
And that's really nice for adding, like you were saying.
It means that in some cases, Coconut code actually can be significantly faster than the equivalent Python code.
In most cases, at the very least, it's usually not slower just because it really is Python.
It just compiles to it.
Yeah, that's really cool.
And you could, of course, write those optimizations yourself because after all this does compile a Python, you could write what the compiler wrote.
But that's a much harder deal, right?
The goal is to have super simple code that is actually optimized.
Yeah, exactly.
The nice thing about the compiler, you can look through the compiled code.
It'll just be a file right there.
But you'll see that a lot of it really does get very complex, very hairy, very, especially with pattern matching.
A lot of it gets really weird and hard to read because pattern matching can get very complex very quickly.
And having a compiler figure out the sort of ways to implement all of that for you is really nice.
Yeah, the way I think of it is people are very bad at writing state machines.
Compilers are really good at it.
Sometimes you end up with stuff like that, right?
So speaking of debugging and trying to understand, like the thing you're going to actually debug when you run a debugger, be that some CLI one or something like PyCharm, you're going to see the transpiled compiled output, right?
So how do I know if that maps back?
Like, where does this map back to this funky syntax that I maybe have in my Cocoa file?
Yeah, so that's an absolutely great question.
Debugging is, of course, a huge, massive part of what every programmer does all the time.
So Coconut has a really clean, simple story for that.
So you can pass the line numbers flag, which is just minus L.
And what that does is it appends to every line in the compiled Python a comment that says, take a look at this line in the source code that produced this line in the compiled code.
Then you do pdb.setTrace, you get an error, and you see the lines that that error is referring to, and you'll see on those lines comments that are telling you what line in your source code caused that exception.
What line in your source code are you tracing through?
All of that stuff you can see, and you can just look at that line number, you can go right back to the source code without having to really worry about and deal with the compiled code at all.
So that way, when you're debugging, you don't have to do any context switching.
There's also another option, the keep lines option, which actually, instead of a line number, will just put the entirety of the line, and it'll just paste it right in there for you as well.
So that's another option.
Yeah, those are both pretty good stories.
That's cool.
So what about parallelization primitives?
Coconut tries to make parallelization as easy as possible because you can have all of these nice immutable data structures, and ideally, you want to be able to use them in a nice way.
Of course, in CPython, at least, Python fights back against you a little bit there.
You've got the global interpreter lock.
But what you can do, what Coconut provides, is two primitives.
There's a parallel map and a concurrent map, which are multi-processed and multi-threaded, respectively, which take the most basic of the functional programmer's operations, and the one that is most easily parallelizable, the map operation, which just says apply this same thing, the same function, to every element.
of this sequence, this data.
And it allows you to really, really easily do that operation automatically in multiple processes or in multiple threads if you're doing I/O bound stuff such that you don't have to mess with any fancy libraries.
You don't have to mess with anything fancy whatsoever.
You just swap out wherever you're doing the map operation, that really parallelizable operation with the parallel version, and you're automatically getting all of the benefits of running that in parallel.
And, of course, behind the scenes, it's using multi-processing and it's pickling everything.
But yeah, that's really cool.
So basically, it's still a blocking function as far as your code is concerned.
But the internal representation, maybe it changes the order in which it processes them and it just fans it out.
Right.
All right.
Awesome.
And then one final feature we should talk about maybe is partial application.
Is this your dollar operator?
Yes, but the dollar operator is a little bit more than that.
So the dollar operator in Python in Coconut just means lazify this.
It means take this operation in Python and make it lazy instead of doing the Python thing.
And so that means different things in different contexts.
But there are sort of two.
There are two contexts where it's used.
So the big one.
Yeah, you put it right before a function call.
And that means instead of actually doing this function call, I want you to do it lazily.
And don't do it until I actually tell you I want it.
And so that is partial application.
That says, here are the arguments that I'm going to pass to this function when I actually call it.
But I might pass more arguments in later.
And so for right now, you can just throw these arguments in and hold them there.
And that's that partial application.
The other usage of the dollar sign is for indexing, slicing with brackets.
And in that case, it's a lazy form of that as well that doesn't actually perform the operation.
And until you ask for the data, like an iterator, and lets you do it on arbitrary iterators.
And so you can, for example, slice, do sort of complex slicing operations on iterators instead of just on lists or tuples, which lets you make use of the laziness of iterators in a much more effective way.
Yeah, that sounds really pretty awesome.
You definitely have some cool uses and examples in your tutorial.
So one of the things that you talked about in the tutorial is the integration or the capability to use Jupyter or IPython notebooks.
And so when I was playing your project, I'm like, oh, I was just at PyCon.
I just saw Jake Vander Plaats' really cool science-y keynote and got me excited about Jupyter.
And I've, of course, played with it before, but, you know, not a lot.
And I'm like, oh, I'll just explore your library through Jupyter.
And that was really fun.
So you have pretty good support for that, right?
Yep. So Coconut has support for Jupyter through both a kernel, which means instead of running your code through IPython, you just select Coconut instead.
And it works exactly like IPython, including, and this is actually somewhat of a new feature, including support for things like IPython magics and all of the sort of nice, fancy stuff that IPython throws in there.
And then sort of on top of that, you have support for all of the Coconut utilities, all the Coconut language features as well.
And so it's basically just like an IPython notebook, but instead of writing Python, you're writing Coconut.
If you only want to do a little bit of Coconut, you can also use Coconut as an extension inside of IPython.
And then it'll just take all of Coconut's built-ins, give you access to those.
And whenever you want to use Coconut-specific syntax, then you just do the align or block magic specifically just to run the Coconut code.
That looks really cool.
And of course, data science type of work is a place where functional programming would really be applicable, right?
Absolutely, yeah.
The stuff that people do in data science and machine learning, it really does apply to the functional paradigm really well.
Because a lot of that stuff is, first of all, it's data transformation.
Instead of like a lot of the very heavily stateful stuff that happens in other areas of programming,
a lot of that stuff, I would argue, still can benefit from a lot of the features of functional programming.
When you're doing something that really is fundamentally, it's just got the one data that you're passing along.
I've got, this is the data that I collected.
I want to do some statistical transformations on it.
I want to get insight into what it's like.
What you're doing is you're passing it through transformations at each point where the functions themselves are sort of stateless transformations.
And that is exactly the paradigm, exactly the approach that functional programming is built for.
So it really does lend itself well to being able to make use of a lot of these constructs from functional programming.
Especially like easily parallelization, if you just want a down and dirty, really easy way to just like process this data faster.
And a lot of the coconuts, very powerful utilities for working with iterators so that you can construct your data and work with it in a lazy, lazy fashion.
So you only have to deal with what you really need.
Right.
When you have billions of rows, but you only want to find a few of them.
Lazy is good.
Yes, exactly.
Another area it sounds like this might be really helpful is in finance.
I feel like that functional programming gets applied in that area a lot as well.
Yeah, OCaml is really big there, for example.
And so that's totally true.
It's another area where you really want to be able to do a lot of the transformations on the data to be able to see what's happening.
As well as one of the nice things about using immutable data structures is you can always really easily just take a snapshot.
You're just like, okay, give me whatever the immutable data structure was at that point.
And you know once you have a reference to it, it's never going to change.
And so it's very easy to, like if you're doing finance, you want to see, like, okay, what was it like at this point?
You can really easily just store references to immutable data structures because you know once you've got a reference to it, it'll never change.
That's really interesting.
Yeah, that's cool.
Yeah, so that's another feature that is really useful, particularly in finance.
Where else do you see functional programming really, people benefiting from adopting it?
I'm a believer in functional programming being very broadly applicable in almost all cases.
Like, you know, I said I worked at Yelp.
And while I was there, one of the things that I did in my spare time was I, you know, went through some of the code base and tried to rewrite some of the things in Coconut to try to get it working.
And even in, like, like a web application, even in something that doesn't seem functional at all, a lot of those constructs, just making, being able to make use of them gives you a lot more power and being able to define the logic in a simpler, easier manner that I think is really basically always applicable.
Yeah, awesome.
If I go to PyPI and randomly grab a package, could I use it in a Coconut app?
Like, are there restrictions where this doesn't work?
Yes, absolutely.
In fact, you could use it regardless of whether that package was built for Python 2 or Python 3, because Coconut, of course, can compile to code that works on either version.
But yeah, because Coconut compiles just to Python, anything that you would be able to access, anything you would be able to do from Python, you can do from Coconut.
So that includes importing any package that you want to import.
Also, the vice versa is true as well.
If you want to, from Python code, import and make use of anything written in Coconut code, that is also really easy to do, you should, because the Coconut code ends up as Python code.
And so it's really easy to import that as well.
You basically ship the compiled Python files as the deliverable, right?
Very cool.
I think we're getting close to the end of the show, so we should probably start to wrap it up.
I'm going to ask you about your favorite editor.
But before we do, let me ask you an editor question about Coconut.
So one of the things that I really like about editors is when they remind me what features are on a class or in a module and tell me what I have it right or wrong or give me auto-completion and things like that.
Like, do I give that up if I take on Coconut?
So that's a good question.
So the answer is we're working on it.
So right now, you can.
There is one method that I have tested that does work with that.
If you use Jupyter console, I know, and I think the notebook as well, you can get the Coconut's Jupyter or IPython kernel to do some auto-completions for you.
I think, as far as I'm aware, that's the only one we've got so far.
But I'm working on it.
That's definitely, you know, there's other people that's working on it as well.
That's definitely something that should be coming out in a more broader way pretty soon.
I'm going to try to add it into Coconut's just basic command line interpreter as well.
Yeah, it would be great.
I mean, it's already really cool.
But it would be even more cool if it could help us along the way, right?
If you could get into Sublime, VS Code, PyCharm, those sorts of things, right?
Yep.
Definitely a cool feature.
Being worked on for right now, try using the Jupyter IPython.
Nice.
Okay.
And so then let me ask you, if you're going to write some Coconut or Python code, what editor do you open up?
So I use Sublime.
I'm a Sublime fanatic.
I love Sublime.
I use Sublime for everything.
I write my school notes in Sublime.
There are now a bunch of highlighters for Coconut, but the Sublime one, that was the one that I wrote.
That was the sort of first one to be made.
I'm the one that maintains that.
I, of course, use that whenever I write Coconut code.
So yeah, I love Sublime.
That's definitely my editor of choice.
Nice.
And so there's also many, many, many PyPI packages, over 100,000 now,
which is totally awesome.
And let me go ahead and throw out Coconut as one of the really cool packages there.
But maybe give us another one.
Yeah, yeah.
As you were saying, pip install Coconut.
But yeah, so my favorite PyPI package would definitely be PyParsing.
So PyParsing is awesome.
It's a really cool utility for being able to define very simple grammars and really complex grammars as well,
just in pure Python and then parse against them.
Coconut's compiler is pretty much entirely written in PyParsing.
So you can tell that I really like it.
It's really powerful.
It works really well.
Coconut pushes PyParsing almost to its limits in a lot of cases,
where it's the point where I had to, you know, submit a bunch of issues in the development of Coconut to PyParsing.
But all of that's been fixed.
The newest version of PyParsing is awesome.
It works really well.
Would definitely recommend checking out PyParsing.
I actually used it for another project while I was at Yelp,
which allows you to automatically refactor code by defining PyParsing patterns.
Yeah, it looks for like code debt and duplication type things, something like that.
Yep, exactly.
It lets you define patterns using PyParsing grammars,
as well as a bunch of sort of other Undeat specific stuff.
And then you can define a like replacement function,
and it'll scan for the grammar and then replace it with that.
And so you can use that to really easily refactor code.
Cool.
Yeah, that's a great recommendation.
And I think it's really neat that your work actually expanded PyParsing a little bit.
But also its existence made your work pretty much possible, right?
Yeah, it's a symbiotic relationship.
It definitely is.
Definitely it is.
Okay.
So this brings us to the end of the show.
You know, final call to action.
You have quite a few people who've starred this and are playing with it on GitHub.
Are you looking for people to kick the tires, to contribute?
What's the story?
So yeah, so Coconut is built on GitHub.
Everything's on GitHub.
Definitely, definitely check out the GitHub.
Start on GitHub for sure.
I would definitely recommend trying to at least take a look.
Go through the tutorial.
Take a look at the documentation.
Take a look and see if, you know, maybe this is something that you could really make use of.
I, of course, think it's really cool and that people can really benefit from it.
And if you have any questions, if you want to look around, there's a lot of resources for that.
You can check out Coconut's Gitter, which is a chat room where you can just ask questions.
And then there's a bunch of Coconut developers there, including me, that can just answer questions, check that regularly.
You can also check out all of the sort of documentation resources.
There's a frequently asked questions, the thorough documentation for all of the specification on the features and the tutorial to sort of give you basic introduction.
And then, of course, if you are interested in contributing to Coconut, I would love to have more people get involved, more people take a look.
It's all open source.
Just take a look at the issues, fork it, make changes, submit a pull request.
If you want to ask any questions about it, if you're trying to get started, definitely goes back to the Gitter.
Just ask around on Gitter and I'd be happy to help anybody out there.
So, yeah.
Yeah, yeah, awesome.
And if people are thinking of contributing, like, what kind of crazy language do they have to learn to, like, work with this?
Like, what's it implemented in?
Python!
Yeah, that's awesome.
I noticed in the GitHub is to be believed, you know, click that little bar and I'll tell you the languages used.
It's 99.7% Python and 0.3% makefile or something like that.
Yes, there is one makefile.
So, I hope you don't shy away too much from having to deal with that.
But, yeah, no, it's all Python.
Coconut, the compiler, just like the compiled source, is written in Python that is intended to be universal.
So, it works on 2.6, 2.7, 3.2 and above.
But, yeah, it's just all just Python, pure Python.
All right.
Well, this is definitely an interesting project you have going and I'm happy to see it succeeding.
And thanks for sharing it with everyone.
Absolutely.
Thank you so much for having me.
It was really fun to be here.
This has been another episode of Talk Python to Me.
Today's guest was Evan Hubinger.
And this episode has been brought to you by Rollbar and Hired.
Rollbar takes the pain out of errors.
They give you the context and insight you need to quickly locate and fix errors that might have gone unnoticed until your users complain, of course.
As Talk Python to Me listeners, track a ridiculous number of errors for free at rollbar.com slash Talk Python to Me.
Hired wants to help you find your next big thing.
Visit talkpython.fm/Hired to get five or more offers with salary and equity presented right up front and a special listener signing bonus of $600.
Are you or your colleagues trying to learn Python?
Well, be sure to visit training.talkpython.fm.
We now have year-long course bundles and a couple of new classes released just this week.
Have a look around.
I'm sure you'll find a class you'll enjoy.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct RSS feed at /rss on talkpython.fm.
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.
Corey just recently started selling his tracks on iTunes, so I recommend you check it out at talkpython.fm/music.
You can browse his tracks he has for sale on iTunes and listen to the full-length version of the theme song.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Smix, let's get out of here.
Stay tuned.
I'll see you next time.
Bye.
I'll pass the mic back to who rocked his best.
Bye.