Programming Throwdown - 144: Kotlin Coroutines with Marcin Moskala

Episode Date: October 10, 2022

Today we go back to our programming language roots with author, KT Academy founder, and Kotlin rockstar Marcin Moskala.  We talk about how Kotlin makes itself doubly useful for app and backe...nd development. 00:00:55 Introductions00:01:38 Java frustrations 00:09:37 Why a well-organized typing system is important00:11:59 What Kotlin is00:14:58 Obsidian 00:20:13 Learning new things can be a prudent future investment00:23:46 A pleasant coding experience00:26:41 Co-routines in Kotlin00:34:37 Where co-routines are best in app development00:44:54 Thread balancing in practice00:57:39 Kotlin’s integrated cancellation mechanism01:05:10 Getting started with Kotlin01:18:16 FarewellsResources mentioned in this episode:Marcin Moskala:Website: https://marcinmoskala.com/Twitter: https://twitter.com/marcinmoskalaKT Academy: https://kt.academy/Kotlin Learning ResourcesMarcin on KT: https://kt.academy/user/marcinmoskalaKotlin Coroutines: https://leanpub.com/coroutinesEffective Kotlin: https://leanpub.com/effectivekotlinFunctional Kotlin (Early Access): https://leanpub.com/kotlin_functionalMore Kotlin Publications on LeanpubInformation Organization ToolsWorkFlowy: https://workflowy.com/Obsidian: https://obsidian.md/If you’ve enjoyed this episode, you can listen to more on Programming Throwdown’s website: https://www.programmingthrowdown.com/Reach out to us via email: programmingthrowdown@gmail.comYou can also follow Programming Throwdown on Facebook | Apple Podcasts | Spotify | Player.FM Join the discussion on our DiscordHelp support Programming Throwdown through our Patreon ★ Support this podcast on Patreon ★

Transcript
Discussion (0)
Starting point is 00:00:00 Hey everybody, this is a super awesome episode. Actually, it's been a while since we did a language on the show, despite the fact that that is our tagline. We've covered a ton of languages. We definitely want to go back and do, for example, C++. That episode is something like 12 years old now.
Starting point is 00:00:41 But we've been on a really long journey talking about user experience, talking about, we talked about trees, tree data structures, a whole bunch of stuff. I'm really excited to come back to languages. And for that, we have Marcin Moskawa here, who literally wrote the book on Kotlin. He's the author of a variety of Kotlin books, including Effective Kotlin and Kotlin Coroutines, Android Development with Kotlin. And it's a real pleasure to have you on the show, Marcin. So thanks for coming. Thanks for having me here. Cool. So we definitely want to get into Kotlin and what are code routines all that but let's start with a bit of background you know what kind of what's your path and what kind of got you to the point where you are you know writing these books and you're you know really diving headfirst on a Kotlin you
Starting point is 00:01:35 know every day what kind of led you to that I mean my journey with Kotlin itself has started with frustrations from Java. I like to talk about it a few years ago because I've built a huge amount of frustration back then and Kotlin helped me release it. Now I barely remember that because I'm using Kotlin for over seven years, I believe. And I nearly forgot Java. I'm still using a variety of different languages for different purposes. But Java is one of the languages I'm trying to forget about. Okay, so what made you write all that Java in the first place? So did you go the college route? Or did you go straight into industry from from high school or how did that play out oh that's mixed a lot so i i was very into the college life i actually was doing two faculties so two different courses on university, having internships on both of them. But then I just had this life-changing moment
Starting point is 00:02:50 when I decided to go to the Erasmus. That's the program where I can go to the other country, live there. I spent half a year in Rome and I decided that I just need to get independent and start earning my own money and live in my own way. So after coming back, I started working,
Starting point is 00:03:12 which was quite crazy, having two faculties and also a job. It wasn't full-time initially, but it was enough to survive. In the meantime, I was working as a developer. I finished those two degrees. And so my career mixed both of those paths. What were your degrees? Were your degrees technical or was it something else? One was computer science. Another one is closer to telecommunication. Ah, okay, cool. Nevertheless, the story with Kotlin
Starting point is 00:03:50 has started for me when I worked as an Android developer. And I was one of the early adapters of Kotlin. And back then, the community was, you know, I mean, community is still very positive, but it's absolutely incomparable what was then and what is now. You know, our community grew so much that no one, I mean, you cannot know all those people. There are literally millions of people using Kotlin. Back then, it was a very small hipster community
Starting point is 00:04:28 where we all were passionates and we were all supporting each other. And it was so, so fun. And I just wanted to give as much as I could. And I was writing about Kotlin and speaking about Kotlin and I was truly passionate about promoting it I still am in teaching Kotlin and teaching programming in general but you know that's that's not the same yeah I was I did a lot of hiking yesterday and so for some reason metaphor kind of comes to mind where if you're hiking this trail that's really common, maybe it's paved or something like that, then you can really hike it by yourself.
Starting point is 00:05:12 But if you start going out in the wilderness, then you kind of need a way to reach somebody if something goes wrong. And so in the beginning, when you're riding Kotlin for Android, you're kind of out there. And so you need a lifeline, especially if you're doing it for work and it has to work, it's not just a hobby, then you need a community. You need somebody that you can go to who is Uber expert and you can say, look, I'm getting this really esoteric error,
Starting point is 00:05:41 please help me. And now maybe the path is just so well traveled that you don't have to really socialize to get your app done. So it's just, you know, a blessing and a curse at the same time. Yes, that and that does change a lot. I remember when Google announced that Kotlin is becoming the back back then it was another language for Android. Right now it's the primary language for Android development. But I remember the day when they announced that it's becoming another language for Android development after Java.
Starting point is 00:06:20 And I was like, okay, we are opening Champagne. It's a huge day for us and a friend of mine who was a bit older for a bit longer in this programming community
Starting point is 00:06:36 he was really sad and he just looked at me and he said we just stopped being hipsters and everything changes now and uh i believe like a year later he left kotlin and he started another big thing so oh what is this big thing what is his next big thing he he he got um into eternum and all those smart contracts. Oh, okay, got it. I'm not sure if this truly became a big thing, but I've never truly researched that.
Starting point is 00:07:10 But he was very fascinated when he started that. Wow, yeah, what an innovator. I mean, I don't know very much about smart contracts either, but it's almost a household name at this point. Yeah, I mean, there are many people like that um i i had a pleasure to work in quite a few startups and one thing that i truly enjoyed is the mindset of people that people just want to work on the break changing things and and change the world and do amazing amazing things and many of those people when startup finally becomes a serious
Starting point is 00:07:47 company many of those people can stay there and make a great money but they decide to leave it instead to to work on another big thing yeah that's right wow as. So, okay, so you were finishing up university and you're building Android, you're working on Android apps and writing a lot of Java and hating life. And you had a life-hating factory and then a factory implementation factory and you're just, oh my God, why do I have a million different factories and like every callback has to be a class. And so it's just driving everyone crazy, right? So, well, maybe you could talk about, you know, I threw out some stereotypes there, but what are the things specifically that really bothered you about Java? I think that the Kotlin in its most basic form is nothing really new. There are new things right now, like coroutines or multi-platform capabilities, and they are big, okay?
Starting point is 00:08:51 But the base of Kotlin is just, I believe, how Java should look like. It is how I think Java would look like, more or less, if it were making hard decisions and evolving as it should evolve. You know, of course, the big problem of Java is backward compatibility. They do not change to not break people's code. So I'm not saying that Java made a poor decision. I'm just saying that if Java would make the changes it should make, in my
Starting point is 00:09:27 opinion, it would end up looking something like Kotlin looks like right now. Plus it has some things that were designed well from the beginning. So Kotlin has a really well-organized typing typing system, something people do not see as important, but it's extremely, extremely important from the perspective of using our code. So when you say organized type system, are you talking about like the type hints and the type inference? So you could say, you know, val x equals three, and you don't have to go and find out, is it an int or a long or do you have a lot of that or what makes it organized? So for instance, in Kotlin, from the beginning, you have a type to represent nullable and not nullable types. Ah, right.
Starting point is 00:10:21 What is extremely important, because only then you can have proper type safety mechanisms, something that is still not very well implemented by most modern languages. And what is more, Kotlin made a very strict relationship between those types. So a nullable type is a supertype of not nullable type. What opens a door for many important use cases. In Kotlin, everything is an expression. We also have a nothing type, an empty type, that is a subtype of all the type, but has no instances. It's another thing that seems minor from people who do not use that,
Starting point is 00:11:01 but it's really, really important on some use cases that allows language to to truly behave well and those are those are small things that are very hard to repair in the language once you publish that but that that were done really really well in in kotlin from the beginning cool yeah that makes sense what actually happens under the hood when you, is Kotlin a JVM language? So does Kotlin compile down to the JVM or is it something different entirely? In general, Kotlin is a compiled language. So it is compiled to something more simple. And in the version that is most often used, it is compiled into
Starting point is 00:11:45 JVM bytecode, just like Java. However, there are different flavors of Kotlin, or you can say platform targets. There is a Kotlin.js that is compiled into JavaScript, and there is Kotlin native that is compiled into the native code. Why is it important? On Android, it is important because it allows us to make libraries that are used both by Android and by iOS. So we can easily make a common part. And teams like to include more and more on those common parts. Business logic, you know, this is generally the same for both platforms.
Starting point is 00:12:27 Even views, there is this new approach, the Jetpack Compose library that allows you to create views in a pure Kotlin using a Kotlin DSL in a really nice style with a nice auto completion and with absolute type safety. And you know, projects in Jetpack Compose can be compiled to JVM and run on Android or on desktop, but they can be also compiled into JS and be displayed as a website or be compiled into a native code
Starting point is 00:13:07 and be a native application for whatever system you want. So that's a new thing and very, very powerful that comes from the fact that Kotlin is a multi-platform language. You can use Kotlin to write on any of those platforms,
Starting point is 00:13:25 or you can use it to write a module that can be compiled into multiple platforms at the same time. How does the iOS work? So you would compile to like a native library. You'd have to somehow create some kind of Objective-C interop or something, right? Yes, exactly. So you could say that the result code is the same
Starting point is 00:13:46 that what you would have if you would compile an Objective-C. And yes, Objective-C is used here to interop with Swift or with Objective-C projects. Oh, interesting. Very cool. Does it generate the interop layer for you? Or do you have to write that yourself? It generates it. Oh, wow. Very cool. Does it generate the interop layer for you? Or how did you have to write that yourself?
Starting point is 00:14:06 It generates it. Oh, wow. That's super cool. I'm learning things using a flashcards in a program called Anki. And I wanted to make a notes that are automatically generating a notes for this Anki program. And I wrote a program for that in Kotlin. I default in Kotlin JVM. But to transform my notes into Anki or Anki deck into notes because it goes in both directions I needed to start a JVM program every time I did not like that and then I figured out I'm using the Obsidian note for it's a program for for a notes for quite a popular one recently where you write all your notes in in markdown and i figure out that you can make a plugin for obsidian and if you write
Starting point is 00:15:13 a plugin for obsidian you can add a button that starts some process basically and i migrated this Kotlin code from Java into Kotlin.js and used it to make a plugin for Obsidian from that. It was very easy. Practically no effort needed. I think the only thing that I needed to change is that I was using the files API and I just needed to get rid of that. And that's it. Everything else worked exactly the same way. And I'm still playing with that, but I do have it working. So I now have a Obsidian plugin where I have button, you know,
Starting point is 00:15:58 push to Anki or pull from Anki. And it does work. I'm still working on that until it is stable until i announce that and publish it but for my own use it is already usable and and it did not take so much time yeah yeah that's really really cool so yeah actually obsidian looks awesome i just went to obsidian.md and took a look. I use Workflowy. I'm not crazy about it. I'm definitely going to check out Obsidian. This looks awesome. But yeah, as someone I've only made apps as a kind of a hobby. And so I've never had a strong desire to make an app for
Starting point is 00:16:43 iOS and Android. I mean, the same app. And so I always kind of wondered how people dealt with that. And this seems like a really clever way where you write in Kotlin and now you get your business logic in a shared library that then you interact with from your main view code. It's really cool. So you were working on apps in Java. And at some point, you either had to convince your company to switch to Kotlin or you had to change jobs.
Starting point is 00:17:17 What happened there? And how did that play out? I needed to change jobs. I mean, back then, there were maybe a few companies in Poland using Kotlin and I sent resume to probably all of them. And you know, Kotlin was still in beta back then and no big company wanted to use it. However, startups did use that. So the company that accepted me was a doc planner. But I probably don't know about it
Starting point is 00:17:55 because it's not present in the US. It's present in some Europe and a big part of South America. That's a service where as a doctor, you can register and people can rate you. You can have calendar and it's literally like an assistant for doctors and patients can, you know, find the best doctors and can check their prices. Yeah, that's interesting by, you. By being passionate about this early technology and then picking companies that are using it,
Starting point is 00:18:31 you're kind of by definition picking companies that are sort of on the cutting edge. And for them to take a risk, it means that their leadership must be pretty technical. It's kind of like, it's really interesting. It's like, I feel like it's a good signal for picking companies to join, right? If they have this sort of same passion that you do about some emerging technology, then I think it's a really good way to build alignment.
Starting point is 00:18:57 Yes. I even heard that it's a strategy of some companies that they intentionally use those new and untested technologies so they find people who are kind of crazy, who are willing to have less money and probably more work for doing what is their passion and what they love to do. Also it's a good strategy for companies like startups because it's actually easier to find people i mean i heard so it is easier to find people in those kind of technologies because you know developers pretty often want to be ahead of others in terms of technology. And companies are more often unwilling to use something that is not yet tested and proven to be working well. All right.
Starting point is 00:19:55 So Patrick and I are taking notes here. If one of these days we ever start a company, we'll make everyone write in Piet or that language that's all brackets or something. I'm just kidding. But that's amazing. I mean, the other thing too is it's a way for you to invest in your future. So if you go to, let's say, maybe a bigger company and they're doing PHP, just like everyone else is doing PHP and you learn php that's great but if you can join a company that's especially if you believe like if you have a crystal ball and you know this language is going to be really big um and you join a company that's
Starting point is 00:20:36 using it early on you're kind of investing in in your future self yes i always seen it as a as a bets we make you know they're like those waves that you can go with um there are those old and lazy waves like java or python that i really like and respect but it is also um not uh not pushing you much you, because there are already plenty of people who know those languages, who have experience, who are teaching it, who have materials, etc., etc. So it's a very safe way to choose a big language like this one, but it's not something that will by itself push your career. But choosing something that is new and risky is, you know, on one side, it's very risky because this technology might die, literally. But if it goes far, it can push you together with it. By the way, another thing that I truly believed back then,
Starting point is 00:21:48 I remember one thing was Kotlin that really inspired me, that I was really fascinated about. But the second thing I was truly passionate about was this multi-platform library called RoboVM. It does not exist anymore. It was a really nice idea that you can write code in Java or Kotlin that were supported and this code
Starting point is 00:22:15 worked natively on Android but it also was compiled into a native code on iOS and so you could also make multi-platform applications. So what happened to that? I believe that Microsoft just bought it and killed the project. Oh, yeah, that happens.
Starting point is 00:22:39 And yeah, and so all the people who invested their time and energy into this fascinating project, you know, lost it. I mean, you know, that almost happened to Java. You know, I mean, when Oracle acquired Sun, there was a period of time where people were uncertain about the legality of using Java and writing your own version of the JVM and all of that. And at that time, people were
Starting point is 00:23:06 wondering if Java was really going to survive this legal battle. And I think it's just at that state where it's too big to fail or too big to fall or what have you. But I've seen a lot of JVM languages, Scala, Kotlin. There's another one that I'm totally drawing a blank on. It was based on Scheme, but there's a bunch of these that run on the JVM, but are slowly kind of eating away at Java. My guess is Java is stable or on the decline, but I'd have to look to actually see the data on that. Yeah, all the data indicate that. Ah, okay. Yep. There you go. So yeah, the the type safety and what i noticed when i um so i wrote a uh my own version of google photos so basically i have a s3 bucket and whenever i take
Starting point is 00:23:55 a photo my phone waits for wi-fi when it gets wi-fi it looks at all the photos that it doesn't already have on that bucket and it uploads them. And so I have just a simple Google Photos clone type thing. And when I wrote it in Kotlin, there's a few things that really stood out to me. I mean, one was it was literally a decade since I made an Android app. So the whole ecosystem is way, way better now than it was 10 years ago. But it felt like I really enjoyed the editor, the integrated experience and all of the sort of quick fixes that were happening. And even the fact that I could, one thing that really shocked me was I could actually take Java code from Stack Overflow
Starting point is 00:24:38 or Java files from other projects, and I could convert them to Kotlin. And it could even in line convert blocks of Java code to Kotlin. That really struck me. It's just amazing how that, because it's not trivial to do that. I found that really pleasant, really surprising. Yes, that's from the beginning. Also, you can pretty easily migrate the whole project and that works. However, of course, it's far from being a good Kotlin code because it's a javish code. And the next step is to start using Kotlin idioms to improve readability and safety of this solution. But yes, a simple solution can be done by this auto transformation and it works really nice. Yeah, I mean, it's a great way to kind of get started.
Starting point is 00:25:33 And as you said, you can see what's going on there and then rewrite it or update it. Yeah, there is actually a cool tool that many beginners use. So if you have Android Studio or IntelliJ open, you can just go into tools, Kotlin, show Kotlin bytecode, and you can see what your Kotlin code is compiled to. So if you're a fan of JVM bytecode, you can read it there. If you are not, there is this button decompile, and this button decompiles your bytecode into Java.
Starting point is 00:26:05 It's a strange journey because we compiled Kotlin into JVM bytecode then they compiled it into Java and you can see how it works. That's a very useful tool for those who come from Java. They are learning Kotlin and they are trying to understand how something works. You can just see how this code would look like if it were written in Java, any code. Yeah, that is super, super cool. If I remember correctly, or maybe I'm wrong about this now, but at the time, Java doesn't have coroutines, right?
Starting point is 00:26:39 So if you write coroutines in Kotlin, how does that end up? And you try to decompile it. Do you get an error or what actually happens there? Okay. So maybe I will start with what are coroutines? Yeah. Okay. Yeah, that's true. It's a good point. So people often say that coroutines are like lightweight threads. I think that's, I mean, it can be a good start as it might be a useful metaphor to understand that they are lightweight and they are kind of like threads. But it's also very confusing because coroutines are not threads. So coroutines are already present in many languages in some limited form.
Starting point is 00:27:31 Coroutines are present in JavaScript, in Python, in C Sharp. Any async await block is a coroutine. Any generator is a coroutine, but a very limited use of a coroutine. So now what a coroutine is. Coroutine is a piece of code, some kind of block that can be suspended at any point. You know, later you can resume it from that point. So the word suspended is very important because it's not blocked. It is suspended. So it means that when you suspend a coroutine, what you have is a continuation object. This is an object that has all the local state, literally something like call stack. So all the local variables of this function, of the function that called it, of the function that called it, etc. etc. So that's what continuation has. And this object is like a save. You can
Starting point is 00:28:34 keep it in your local memory. Formally, you can even serialize it and later deserialize it. Nevertheless, at any point you can resume it and continue from where your function stopped. So it means that you can literally jump in the middle of the function and, you know, start from there. Perfect implementation of coroutines requires a control of platform to, you know capture this this stack and restore it kotlin does not have it because it does not control the platform so it simulates it by having those continuation objects that that that store it wait hang on let me let me dive into that because that that blows my mind so so how does kotlin able to store all the local variables?
Starting point is 00:29:28 Is that part of the Java JDK where you can get all of that? It's a simpler concept. So in Kotlin, the functions that can be suspended are suspending functions. They have suspend keyword. Such functions under the hood are passing this continuation object that is a reference to their local state. And this object is used to keep this local state when someone suspends it. The very important thing to notice is that this is not an additional cost. Because I mean, it is, but a very small one.
Starting point is 00:30:03 Because we are not copying this state. We are only adding another reference to it. So if you have a local variable with a list that is placed somewhere in the memory, you know, the variable is a reference to a point in the memory, then the continuation does not have a list. It have a reference to the same point in the memory. So creating those continuation objects is super cheap because, you know, you're not
Starting point is 00:30:34 copying the state. It's like a shallow copy. Yes. It's like a shallow copy, but we want it this way. Yes. We want it this way because, you way because if the continuation is suspended, then the local variables are gone because your execution is finished for this coroutine. But you still have a single reference to that in the continuation. And that's how it works. And that's pretty
Starting point is 00:31:05 smart. Of course, because Java has plans to introduce coroutines. And I believe that they will introduce them in a century or two from now on. And Kotlin is designed
Starting point is 00:31:22 to support that if they finally introduce that. Yeah, that makes sense. One place where I found myself needing to use coroutines, and this goes way back, I wanted to make an RPG game. And this was a long time ago. I was actually in high school, I i think and i only knew c++ and um you know if you've ever played any of these rpgs you go to the town and there's people walking around in the town and you can walk up to them and press the button on the joystick or a keyboard or
Starting point is 00:31:59 whatever and start a conversation right and they have some dialogue that they'll say on command when you're not talking to them they're kind of wandering aimlessly? And they have some dialogue that they'll say on command. When you're not talking to them, they're kind of wandering aimlessly or maybe they have a path that they follow or what have you. And so, you know, each person is kind of, you know, operating on their own timeline. Like you don't want every person in the town to move at exactly the same time.
Starting point is 00:32:19 It would look very robotic and weird, right? So you want to have each person sort of with their own timer that says, okay, you know, a few seconds have passed, let's move to the bookshelf and let's take some steps. Or, you know, I just took a step, now I have to wait a second. And so, you know, again, this is very early. So I thought, oh, I'll just have each person become their own thread. And when they're not not walking the thread will just be sleeping and what i found is yeah you actually can't create thousands and thousands and thousands of literal threads because there's so much overhead there and even a thread that's asleep you know
Starting point is 00:32:56 consumes a lot of resources and it turns out if you have a ton of threads that are asleep you end up running out of cores and it's just kind of a mess right so you end up having to uh do something else or you kind of like visit all of these characters and wake them up and say hey are you ready to do anything and they say oh no i need to sleep for another you know cycle i'll walk next cycle so you go to the next one so every cycle you kind of round robin go through all these villagers you know kind of waking them up letting them do a cycle and then going to the next one and it becomes really cumbersome because as you said if a villager has some internal state it needs to like wait uh you know 27 cycles before taking the next step you have to go and update that internal state and everything now has to be in uh like a you know c
Starting point is 00:33:46 plus plus has to be in like a dictionary or something and so you lose type safety and it feels very unnatural right what's much better is if you could actually have like a you know a not literally a process like a unix process but have like a you know separate routine for each uh uh you know villager and in that routine you could say you know sleep for a second and take a step and do this forever and not have to worry about all the overhead um and let let let the os handle you know keeping the state of all those people and everything and so so uh you know at the time i i didn't know about coroutines, so I had to implement a really ugly way. But I've always found coroutines really elegant,
Starting point is 00:34:30 kind of beautiful way of handling many, many objects that all need to have their own internal state at the same time. Sure. But I will probably synchronize it with a single timer anyway. I haven't done a big game project, but in a small one I wouldn't like having independent timers for different parts of a game, because then your game is overloading your computer, some things are getting slow and now all the elements are, you know, living in their own time. I generally believe there is a tendency to rather synchronize everything with a single clock. And I would rather use objects. However, the actor model seems like something that could be helpful in here. And in Kotlin, we use coroutines for the actor model.
Starting point is 00:35:29 Yeah, why don't you dive into that? So like there's a lot of folks here who have maybe never built an app. They do web or they do backend or something like that. So kind of connect us from sort of the app development to coroutines. When are they used? What's the kind of best use for them and
Starting point is 00:35:46 why are they a good idea okay so there are a few typical use cases so the the most typical one is that let's say that you on your application you need to fetch some data from the internet and you need to wait for those data because it takes some time to get them from your API. The question is, how do you wait for that? So if you block your thread while waiting for the response, you need to well manage threads because there are some threads you should not block. Other threads you can block, but they are expensive and you should not block too many of them. So that's problematic. So coroutines solve that problem.
Starting point is 00:36:31 You just suspend the coroutine when you wait for something and resume it when you got it. Then using coroutines, it's pretty easy to implement as in Kawaid. I mean, they are built into the Kotlin coroutines library. And there are two parts of Kotlin coroutines. There is a built-in support that gives you the capability to suspend, start coroutines, et cetera. And there is a library that gives you tools like async await or sequence generators, et
Starting point is 00:36:58 cetera, et cetera, with yield. And so then pretty often we use async await in a similar way as in other languages, but they are implemented using coroutines. Another thing is that if you are implementing a backend application, as Jason mentioned in here, if you start too many threads, it's a huge cost for your computer. So if you have a pool of threads that you use on your
Starting point is 00:37:33 backend system and you have lots but lots of requests, then you need to start a lot of threads on your pool or you need to make your requests wait, what is not optimal. Each thread is at least one megabyte of data.
Starting point is 00:37:53 Each thread allocates one megabyte of data. It is also a significant cost from the perspective of processor or operating system synchronization. So if you start having, let's say, thousand threads, it's already a visible burden on your processor time, you know, the energy used only to manage them.
Starting point is 00:38:17 And it's already one gigabyte of RAM at least. If you have 10,000 of them, that's very's very very unlikely your application will will work fine and you know in a in a big systems you know the having those numbers of requests is not so hard to reach yeah the other thing is you can really shoot yourself in the foot i have a couple of stories one um patrick and I worked together a really long time ago. And we worked on a project where we were doing some image processing. And we were trying kind of a new way of doing image processing. And basically, this was all we were prototyping something on the desktop.
Starting point is 00:39:06 And I'm pretty sure you can correct me on this, Patrick, but I'm pretty sure what we did was we we created a new either a new thread or a new process for every frame. Again, this is us not knowing what we're doing. And so we couldn't figure out why, you know, right around around 20,000, 30,000 frames, the Python program died. And then we would have to run it again on the next 30,000 frames. And it's because we didn't really know what we were doing. We didn't realize, OK, there's this huge overhead. And what I really need to do is use a thread pool or even better, use async await, which has a thread pool under the hood and takes care of that for you. A similar story, there was actually a period of time where, you know, the street view, which is the Google Maps where you can go down to the street level and see the photos of the street.
Starting point is 00:39:59 That service actually leaked threads. So there was some part of that service that was creating threads and not releasing them, like not cleaning them up. And so there's a period of time. Now, when I say period of time, I'm talking years where the Street View service, a single instance of that service could only live for a few hours because it would eventually allocate too many threads and get killed by the hypervisor. And so the solution for maybe not years, but definitely for about half a year, the solution was to just keep enough services, enough instances up and running. And so for like half a year, Street View limped along with that.
Starting point is 00:40:46 And AsyncAway solves all of that. I mean, you still have to do tuning and all of that if you're performance conscious. But it's much harder to shoot yourself in the foot with AsyncAway. Yeah. So in Kotlin, we use coroutines. We use coroutines. We use coroutines. We start a request. The typical approach right now is to handle each request in a separate coroutine. And those coroutines have their own pool of threads
Starting point is 00:41:16 because the Kotlin coroutines library has a default built-in support for pool of threads so that when you start a coroutine, you can decide on what pool of threads it is supposed to run. And in this case, it will run on the optimal number of threads for your machine. And that is, of course, the number of cores on your machine. So if you have a 16-core server, it will start 16 cores and probably tens of thousands of requests will be on tons of thousands of coroutines.
Starting point is 00:41:57 That is practically no burden at all that are running on those 16 threads interchangeably, only when they are needed. Whenever they are waiting for something like response from database or from another service, the coroutine is suspended. But suspending and restreaming is a very cheap operation. So it's very, very close to the optimal. That is, you know, the theoretical way where, you know, processor only does what it should do. So business logic of yours. Yeah, one thing I always wondered, and I never took the time to do an experiment to find this out. You probably know this offhand.
Starting point is 00:42:41 Let's say you have 16 cores and I create 17 coroutines and they all have a lot of work to do. Does it share time between those 17 or does it finish the first 16 and then do the 17? So coroutines can only switch at the suspension points. So if those coroutines never suspend, what is very unlikely, because we generally use coroutines to do things that are suspending. So if they never suspend, you know, you said 16 and 17, so 16 of them will work until the first of them is done and then the 17th will be able to
Starting point is 00:43:28 start. However, even in such extremely rare situations, there are good practices like using there is this yield function with no arguments that is only a suspension point, only a place where you can have a switch and give other coroutines a time for processing. I use it extremely, extremely rarely, probably only a few times in my life, because it only makes sense in processes that are blocking threads without suspension for a very, very long time. So either doing a lot of work or doing some waiting. But in such a case, there is also a different case because if you have a coroutine that is waiting, you are not using the pool of threads that is designed to be efficient,
Starting point is 00:44:24 but instead a different one that is called dispatchers IO that is designed to be blocked. So there are, as I said, there are different pool of threads for different purposes. If you have things that are blocking, there is a dispatchers IO to be blocked. If you have things that should be CPU intensive, that are doing processing, there is dispatcher's default that has as many threads as you have cores on your CPU. And on Android, the most popular is dispatcher's main, that is a pool of threads that only has one thread that is the main thread, that is the most important thread on Android. So by the way, actually, that's also funny because people think that coroutines
Starting point is 00:45:06 means multiple threads and it can mean that. But pretty often, that's a lazy development, but nevertheless, many companies do that. Pretty often, Android projects run only on a single thread that is the main thread. And it's perfectly fine because it's never blocked so i mean it's not perfectly fine if you do too much work but if you if you are not doing any cpu intensive things only you know a thin client you know fetching data and displaying them it's generally fine because with coroutines you never block the threads you only only use it when you when you need it before you need to use it and that's a that's a valid approach for a very simple applications with no cpu intensive operations that makes sense so so yeah totally makes sense
Starting point is 00:45:57 i think let's use the photos app example you know if i i do a scan using the sqlite i think it's called room the wrapper around sqlite on android but but i have some sqlite query i compare it to my media and i'm forgetting all the jargon here my media service and it says okay i have these 400 images to upload and so i can start 400 coroutines right off the bat. It'll only start maybe eight of them at a time. If I say eight cores, you know, should be or eight threads should be, you know, allocated for this, wait for those eight to finish and do the next one. But I can start all 10,000 of them because the overhead is so low. And then, you know, and then eventually it'll chew through all of those and finish.
Starting point is 00:46:45 What about if something is really CPU heavy? For example, I want to detect faces in the photo on the phone for some reason. I don't actually do this, but let's say as a thought experiment. So it sounds like, correct me if I'm wrong here, it sounds like what you would do is you would create a thread pool uh that's maybe not all the cores because you don't want to you know maximize someone's phone and then you would put these 10 000 requests into that smaller thread pool that's not the main pool or anything like that and then those those coroutines will you know monopolize that thread pool until they're all done,
Starting point is 00:47:25 but it won't make your phone burn a hole through your pocket or anything. Yes, there are tools for that. You can limit parallelism for your usage. The whole chapter, Dispatchers, in my book Kotlin Coroutines is about that. Basically, there are two typical use cases. One of them is exactly what you described. So if you have CPU intensive things, use dispatchers default. That uses as many threads as you have cores.
Starting point is 00:47:57 However, if you think you might use it too intensively, you might starve other processes. What is not good and for such a case we use dispatcher's default dot limited parallelism and we set up a limit and it can be one or two or four or whatever and now you are still using the same threads okay to in the end not use for CPU intensive operations more than you have CPU in your processor, but you limited your concrete kind of use to a certain number of threads to not starve others.
Starting point is 00:48:35 That's the suggested way to do that. Of course, it's not the only one. You can pretty easily create a new pool of threads with a new thread. But if you do that, then if you use your threads to the maximum and dispatcher default is used by someone, but by some other process to the maximum, you are using more than number of cores in your CPU, what is suboptimal for your processing? I mean, it's not a big problem if there is only a few more threads than the optimal one, but it's less optimal than it could be if you would restrict your CPU
Starting point is 00:49:15 intensive operations to the number of cores on your CPU. There is also another case. So another case is with blocking calls. So as I told you, there is a different dispatcher for blocking calls. And this dispatcher also has a limit. It has a limit because it's pretty dangerous to not give any limit at all, you know? Because let's say that you are using some library that is blocking your thread when it fetches something from the internet. And then you start 10,000 processes and you start 10,000 threads. That's what would happen if you would have no limit and probably your app would crash or something like that. So there must be a limit.
Starting point is 00:50:02 And so Kotlin team was thinking about the limits. They've been meditating in the wild for years. And then the light came from the sky and there was the number 64. And that's the default limit. And that's a good limit for Android applications, actually. If you need more than 64 applications for blocking operations on Android, you probably do something wrong. However, it's not such a big limit for backend applications because sometimes in backend we just need to use our memory more to speed up some processes. And for that,
Starting point is 00:50:46 we also use limited parallelism. I think it should have a different name for that, but it actually is the same function that instead of adding a new limitation, it transforms this battery into a new one with a different independent limit. And so you can create a new pool of threads with your own limit. So now why I'm saying about all those pool of threads, why not creating a totally independent
Starting point is 00:51:15 one? So the point is that those pools I mentioned in here, they are part of one big pool, like one lake. So the point is that creating a new thread is a cost and keeping it is also a cost. So the point is that you might need a thread by dispatcher's default and then switch to a coroutine that uses dispatchers.io. And the point is that you are not changing the thread. You can stay on the same thread, but this thread does not count as a default anymore. It counts as an IO right now. So we are reusing resources.
Starting point is 00:52:00 We are reusing the same threads. What's a trick to limit the cost of creating threads? We are just reusing the same threads. What's a perfect mechanism? Because we still have limits that we set up before.
Starting point is 00:52:18 This dislike is infinite. So you can use, IO can use 64 of their default, I don't know, 16. And our custom limited can use 100 and other, and that's perfectly fine. But if there is no need, they are reusing the same threads. They are just, you know, switching them. And that also makes it possible, and it actually is how it works, that pretty often you switch with your operations. So you do something CPU intensive, then you switch
Starting point is 00:52:52 into with another coroutine on the, or even the same coroutine into dispatcher's IO, because you do blocking, then into another one, into another one, and you can do many of those switches while still staying on the same thread. So you are on different moments, you are using limits from different pools, but you are still staying on the same thread, so you do not need to really switch. It's very well optimized in terms of performance on many levels. Yeah, I found that to be, you know, from a developer experience to be extremely pleasant once I figured it out.
Starting point is 00:53:31 There was a bit of a learning curve, but just to give an example, you might want to detect faces in the photo. And then once you've detected faces, you might want to, say, draw a rectangle around them. And so, you know, that second part lives on either, I guess, main or rendering or some thread that isn't sort of this off board process that's going to take a long time, you need to go back to the user interface process, and draw those boxes, or at least tell the system that the boxes are ready. Yeah, it's all done with through this with keyword right it's
Starting point is 00:54:05 it's uh been a while since i saw this code but you kind of say like with this context with that context and you're able to in the same coroutine jump context do different things and then jump back yes with context function allows you to to jump into a different context. So it formally starts a new coroutine, but you might not even notice that. Yeah, I find like anything that avoids message passing is good. Message passing just seems to be really problematic because you now are not writing coding
Starting point is 00:54:40 where you're kind of sending data back and forth between threads. And it's just very easy to mess that up, to have sort of the wrong thread, read the data and starve another thread. And I've just had so many issues with message passing that this sort of like eliminates all of that. The fact that you can jump into different contexts and do work without having to sort of pass a lot of messages back and forth. And when you use a with context, you are suspending the coroutines.
Starting point is 00:55:10 So from a with context, you can return something that will be used on the continuation of the previous coroutine. I mean, I think if you take a big picture and compare what Kotlin has, comparing to what we have on JavaScript or on Python, the async await and sequence builders, I think there are a few things. Because of course, the big point is that Kotlin implemented that so that with this approach, we can implement a lot of things. The support is very,
Starting point is 00:55:47 very powerful and generic. That's a nice thing. Maybe someone will take it in the future, make a new, amazing approach. But now if you compare the Kotlin coroutines library, so the actual tools that we use, The main differences between JavaScript and using Kotlin coroutines in practice is that first of all, Kotlin has a much more powerful built-in synchronization so that if you start a bunch of suspending functions, by default, you are awaiting for them because they do not start a new coroutine.
Starting point is 00:56:23 They are just suspending functions. They are just, you know, suspending function. They are just functions that can be suspended. You can always make them async, but you do not need to. You know, in JavaScript, it's the opposite. Everything is async. You need to synchronize directly. And the synchronization mechanisms are present on many different levels. What is a very nice power of Kotlin.
Starting point is 00:56:46 Another thing is that we have these dispatchers mechanisms, so managing threats. That's a huge, huge power. I haven't seen that on other languages implemented this way. Another thing is cancellation, a very important thing on Android, because pretty often on Android, you open a window, an activity, or some other kind of window, and you immediately close it. So when you open that, some processes start, and when you close it, you should cancel them.
Starting point is 00:57:18 Because if you don't do that, then some processing happens, some processing that never will lead to nothing because it has no views to update then it will try to update those views what will lead to some exceptions in background because those views do not exist so you need to cancel and that's a that's a problem of many other approaches kotlin has a built-in cancellation mechanisms how does that work so so if a coroutine gets canceled, what happens inside the coroutine? It throws an exception, a runtime exception or something?
Starting point is 00:57:51 There is a chapter about that. All right. It's not easy to write. It's not easy to implement a good exception handling mechanisms, you know, because people, if you ask people how to do that, their first intuition is to just stop the process, which is a terrible idea, because pretty often you need to clean up after yourself. And so your intuition is actually really good, because what does happen is out of a suspension point,
Starting point is 00:58:26 there is a special kind of exception thrown, a cancellation exception that propagates and kind of closes everything. That's one thing, that's the part that stops a current process. Also in coroutines, we have this parent-child relationship, the structured concurrency,
Starting point is 00:58:44 another very powerful thing of Kotlin coroutines, we have this parent-child relationship, the structured concurrency, another very powerful thing of Kotlin coroutines. And so when you cancel the parents, it cancels its children. So it also propagates this way. And together with this, you can, first of all, if you have a finally block, it will always be executed when you cancel. So it's guaranteed.
Starting point is 00:59:09 Second of all, you can easily set up some callbacks on cancellation. And we set them on many different layers. So for instance, the libraries that do network calls, they also set up callbacks on on yours on their suspending functions cancellation um because they they probably need to to also clean up some resources to to inform some processes that there is no need to wait for that etc etc yeah i mean one thing i i noticed about doing phone development is how the the os plays a much bigger role like for example the the one that comes out to me is um you know i'd set this up where i didn't want somebody on a metered oh i
Starting point is 00:59:52 didn't i guess i'm the only user here but i didn't want myself on a metered connection like on a 3g or 4g connection to be uploading these big photos to to the s3, right? So I asked Android to set up this, I think it's called a service, and the service only runs if I'm on Wi-Fi. And so if I get off of Wi-Fi, and I have some big upload, maybe I'm uploading a large video, I need it to stop doing that so I don't end up with some big bill, you know, at the end of the month. And in practice, the way this works is by canceling the coroutine that is doing that big upload. And so in this way, the OS is sort of aware of your Wi-Fi state, and it can go and cancel your coroutine. And so as an app developer, I noticed I had to be much more in tune with what the OS can do
Starting point is 01:00:47 and how to handle that appropriately. Yes, that's right. I mean, I was always saying that you need to choose your poison depending on what discipline do you, what kind of development do you choose to do. So of course, in backend, you are mainly fighting with your databases
Starting point is 01:01:08 that they are changing structure or that you need to make operations on databases to make them more efficient. And also with your API, so that how does it look like? What versions do you support? And of course, the spread it and often weirdly packed business logic.
Starting point is 01:01:28 On front end, you generally fight mostly with different screen sizes, with CSS and with reusability of your components. And on Android, I also see that there are two kinds of things you are fighting. One of them is communication with your operating system. Another one is designing your views. So, you know, of course, designing views for different kinds of screen sizes that can be, you know be time consuming and annoying sometimes.
Starting point is 01:02:09 And the second thing is communicating with operating system on many layers. How you handle notifications, how you handle network, what happens in some different situations, you know, is that there are many, many things that a good Android developer should know. I remember there was this function that where you should clean up your resources. But the truth was that in some cases, it wasn't called, it has never been called. Because if your application was stashed, if it was moved to background, and then the memory has stopped,
Starting point is 01:03:00 then it could be killed without invoking the lifecycle. So that people needed to know that they needed to do special tricks to properly clean up some important resources on earlier lifecycle functions. So there are many, many things that are part of fighting with operating systems on Android. Yeah, totally. I remember, you know, years and years ago, the user experience on Android being so jagged, you know, so glitchy, where it would freeze all the time, because people were just doing things on the main thread. And, and I think on iOS, something about Objective C, or there's something in the language where if you did things on the main thread, iOS just wouldn't compile. And so they forced you to keep the main thread smooth.
Starting point is 01:03:49 And then at some point, Android, I don't know if they force you now, but at some point, Android apps became smooth as well. At some point, Android creators started throwing an exception when you made network operations on the main thread. But that's far from perfect. There are still many things that people do on the main thread that they should not. Yeah, definitely.
Starting point is 01:04:13 But yeah, it was a good start anyways, at least. It seems like apps are much more responsive now. Yeah, also phones are faster. Well, that's true, yeah. We have more resources to waste. Yeah, Moore's law rises all all interfaces cool so this is this is really fascinating how can people if someone wants to learn kotlin you have a lot of a ton of folks who listen in who are high school students college students they might be learning their first language in college and
Starting point is 01:04:46 likely not going to be Kotlin. I mean, most colleges are teaching, I guess, Python or Java or C++. So if someone's just getting started in the field and they hear what we're talking about, maybe they want to make an Android app or a backend app and they want to use Kotlin, what do you recommend is the way they get started? So it all depends on from what level do you start. So if you start from knowing other languages like Java or C Sharp, and I think there is a really nice Coursera course made by Andrzej Breslav,
Starting point is 01:05:25 initially the main creator of Kotlin, later co-creator, but head of design team. And also Svetlana Izakova, who is a really, really great evangelist and a great person
Starting point is 01:05:41 and extremely, extremely competent in teaching Kotlin. And I also would recommend a book she co-authored, and that is Kotlin in Action, that pretty well describes all the Kotlin features together with their use cases and some essential information about using them. If you start from the beginning, there should be soon a course on Coursera made by Mita, Facebook. I cannot
Starting point is 01:06:25 tell you who wrote content for that, but I think it will be a really good one. It's part of Android path, but it's written so that it can be started by anyone.
Starting point is 01:06:42 And it's, I believe, Kotlin Essentials. I believe so. I also write a book that is Kotlin for Developers. It's actually a series of books because I couldn't match everything I wanted to explain on a single book. So I split it into three books. It will be Kotlin for developers essentials. I am working on at the moment the functional Kotlin, the second part of the series that I practically finished. It is reviewed at the moment and the different kinds of correctors are applying their corrections. It's already available on LeanPub, but I think it will be available on Amazon
Starting point is 01:07:31 no sooner than maybe on November or December. We are waiting for a surprise host chapter. I don't want to tell too much about that, but we will probably have fascinating topics written by really nice people co-authoring this guest chapter. And there is advanced Kotlin that I'm planning to write
Starting point is 01:08:03 at the beginning of the next year. My books, if this is time for my books. Yeah, let's hear it. My books are not for beginners. The effective Kotlin is now for Kotlin users. So it's for people using Kotlin already. And it's a recipe for getting better in Kotlin. I hope for understanding Kotlin more and for, you know, I included there a lot of good practices and a lot of ideas for a good development. And also Kotlin coroutines is also not directed
Starting point is 01:08:55 to non-Kotlin developers. You need to know Kotlin at least a little bit to understand this book. But Kotlin coroutines deep dive is a position, a child of mine that I directed for Kotlin developers, teaching Kotlin coroutines from the beginning until everything I have to say on Kotlin coroutines. I'm very proud from this position. It's based on a workshop of mine that I conducted for,
Starting point is 01:09:29 wow, probably at least 30 iterations. With every iteration, it was changing a bit. And so I think it's a very well designed and very well thought through book. By the way, the first series of books, The Kotlin for Developers, is also based on a workshop of mine that teaches Kotlin from the beginning. And that's also pretty well thought through.
Starting point is 01:09:58 Very cool. And so you have the workshops and the books. Are the books available on like Kindle or Amazon? Or what's your primary vector for getting the books out to people? So my preference is for people to use a LeanPub because it's a platform where I generate those books. So they are most up-to-date over there. And it's also a platform where I have 80% of income from sales.
Starting point is 01:10:30 Sorry to interrupt, but is it LINPUB or is it L-E-A-NPUB? Lean, like, you know, like lean startup. Ah, okay, okay, LeanPUB. Okay, yeah, so we'll definitely put this in the show notes. And, oh, yeah, there's a ton of amazing books here. Actually, it's my first time on this site. It's very, very cool. There are many amazing authors there.
Starting point is 01:10:53 And I think it's a really great service for writing books for developers. You write your code in a modified markdown, and it generates a really nice output file you have all rights for. So you can print it and distribute it. You can also get this printable version and sell it over there on the KDP. Or you can sell through the platform where 80% of income goes to the author, which is pretty nice. And on Amazon, you know, the money from e-books are funny, are really, really small.
Starting point is 01:11:52 Nevertheless, I see that the sales are much bigger there. So it's important for me that, you know, the books can reach people and that people can read them and learn from them. And that always makes me happy. Yeah, I mean, this LeanPub, I just typed in PyTorch, which is what I seem to be spending most of my time with lately. And yeah, it's extremely great. It tells you directly what the author will learn,
Starting point is 01:12:19 what the overhead is. And it has a bunch of details on the book. You can see the contents. You can get all the previews. Yeah, this is super cool. I'm really glad you shared this with us. There is also a money back guarantee. So if you buy a book, you don't like it, you just, you know, ask, give me your money back. It automatically happens.
Starting point is 01:12:38 So, and I believe you have 45 days for that. Yeah, very cool. Yeah. As someone who, you know, my overall philosophy to folks is to just build something when they want to learn. And so following sort of eating my own dog food there, I did just jump into Kotlin by building this Photos app. And what I found was that, you know, now that we've talked, I realized that the way that I was setting up their coroutines, I was probably creating a lot of unnecessary thread pools.
Starting point is 01:13:12 I think they're called executors. This is this was like two years ago. So I'm drawing a bit of a blank. Yeah, we generally avoid that. Yeah, I mean, this is really fascinating. And so this is so, you know, I think, you know, get started by diving in, we just shared with you some resources that will put in the notes, almost every podcast listener app should have the notes. If not, you can go to programming
Starting point is 01:13:37 throwdown.com. And, you know, when you dive in, you're probably going to make all the same mistakes that all of the rest of us made when we wrote our first code. You can go back and read Kotlin coroutines, some of the more advanced texts, and make your app super responsive and fix other sort of developer landmines and all of that. I think it's a constant learning cycle. Yeah, I actually see it as a problem of coroutines. That's probably the biggest problem of Kotlin coroutines, that they are very easy to jump in and start doing something that somehow works. And it's perfect because coroutines are, I believe, extremely intuitive. So if you try to understand the general idea of how your program works,
Starting point is 01:14:33 they do not disturb you. And when you see the code of coroutines, it seems quite intuitive. That's perfect. But from the other side, it's very easy to do something that makes no sense in coroutines. And you do not know about that. And people often do that. The one thing I pretty often see is people creating jobs. There is this job object. You know, people use it as a context.
Starting point is 01:15:01 And this way they break their structured concurrency. So the cancellation does not work anymore and they have memory leaks. But they do not know about that because they are not tracking their memory. And there are many traps of this one. So it's very easy to use that without understanding that. And as a result, there are many people using that incorrectly, thinking that they are using it okay. And that's the biggest problem of coroutines.
Starting point is 01:15:29 I think that the point in here, I mean, there are languages that are forcing you to do things intentionally. Like by forcing that using a typing system or by the the structures that that that you need to use you need to use things intentionally and that forces people to to understand that to to not use it incorrectly that's that's good but of course one thing is that it makes um makes it very much harder to start with those solutions. Right, right. Is it good or is it bad? You can discuss on that.
Starting point is 01:16:13 But the second thing is that it makes that extremely unreadable. And that's my biggest problem with Eric's Java. I can use it, I can understand it, but it takes me much, much more time. And if you take a student and make him or her read Eric's Java, it's very likely, sorry, that does not make any sense. If you make that person read code using coroutines, it probably might have some question marks, but it will generally be quite clear
Starting point is 01:16:47 of what's the meaning of the program. Yep, yep. Yeah, I mean, it's so true. I was thinking about when I started using Next.js, which is this JavaScript Node.js kind of front-end, back-end hybrid tool. Yeah, I found it very opinionated, and so I struggled a lot because
Starting point is 01:17:06 it would say, oh, you can't do this. You can't do that. But then what I found was that when I was done, initially you want to say like, oh, how can I sort of hack this to get around this limitation? But then after you're going to Stack Overflow and other sites and finding out, oh, no, actually you can design the same thing you want in this other way and that's sort of what the intent is kind of puts you on the right course but you're right you are sort of fighting it the whole way until you reach your transcendence there and so and so the the having it extremely open-ended allows people to get started right away so it's it's a real double-edged sword. Um, but yeah, I found Kotlin to be very approachable. And, um, and so now I think if I did want to release my, my photos app, I would probably have to read your book and, uh, and
Starting point is 01:17:56 rewrite a bunch of it, but at least, you know, getting that first version kind of can give you that sort of dopamine, that adrenaline, you know, that you need to, to feel satisfied and then make the better version. Great. Thank you. Cool. Thank you so much, Marcin. This was amazing.
Starting point is 01:18:12 Really deep dive. I mean, I can, you know, we can tell that you are clearly an expert in this language in this area, and it's been a real honor having you on the show. Everyone should check out Marcin's books. We're going to post all the links in the notes. He also has workshops. You could go to kt.academy and see what sort of workshops are available there. And he's also available on Twitter, twitter.com slash Marcin Moskawa. So for the spelling, definitely check the show notes. I get this all the time where people put an H in my last name and all of that.
Starting point is 01:18:49 So definitely check the show notes, click the link a lot. A lot easier than trying to spell either of our names. It was a real pleasure. And I look forward to kind of staying connected and seeing what the latest is with Colin. Sure, great. I will be happy to appear here again. Thank you for the invitation and hope to see you again. Cool. Thanks, everybody. And everyone, thank you for donating
Starting point is 01:19:12 and supporting the show on Patreon. We really appreciate it. It is kind of crazy economic times. We take a whole hour for us to talk about that. But it is kind of crazy times. Every time I look at the news, it's a little wild. And so I know it's tough out there. I really appreciate everyone's support for the podcast. We put all of that money back into trying to get more kids and young adults on Programming Throwdown and learning about it. And thanks, everyone everyone for writing emails. We get so many emails from folks who, maybe they started listening 10 years ago
Starting point is 01:19:50 and now they're in the industry. It's pretty spectacular. So keep sending those emails. It's a real treasure every time we, Patrick and I get one of those. So everybody, we will see you in a couple of weeks. Commons Attribution Share-A-Like 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 share alike in kind.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.