Let's Learn Kotlin/JS!
with Sebastian Aigner
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
Jason: Hello, everyone. Welcome to another episode of Learn With Jason. Today on the show, we're bringing in Sebastian Aigner. Thank you so much for being here today. How are you?
Sebastian: Hey, Jason. How's it going? I'm actually really good. It's been a long day, you know, being in Europe. It's like half past 6:00 now. But yeah, no, it's pretty great.
Jason: You're on your, what, third, fourth event today? You're just all over the place.
Sebastian: Yeah, this is the third event. I'm really trying to embrace all this, you know, new media, as they say. (Laughter) No, we're doing a bunch of internal livestreams these days. We have a podcast. Yeah, I'm involved in all of that.
Jason: Got to keep it busy, right? The new world of trying to do like DevRel and outreach stuff when you're not able to travel and be in person is just a whole lot of staring into a camera lens.
Sebastian: Yeah, it really is. It's incredible. Like, we've had a bunch of events where you really -- you start to realize how much you feed off the energy of the crowd. When you're just talking to a camera and you make a joke and you have no idea whether it lands. You're just doing some cringeworthy stuff. Yeah, it's tough. You just got to power through.
Jason: This is my whole life, right, as I taught myself that I'm very, very funny because I don't get any feedback. So I just had to believe. So I just stand in front of the mirror and tell my jokes and laugh at my own jokes. So I'm convinced now that I'm the funniest person on the planet. I'm really scared to go back into society and realize that I'm wrong. So I might just stay inside, tell jokes to myself for the rest of time.
Sebastian: I mean, hey, whatever works, right?
Jason: (Laughter) But yeah, so first folks who aren't familiar with you, do you want to give us a little bit of a background on yourself?
Sebastian: Yeah, sure, absolutely. I'm sure there's a lot of people who aren't familiar with me. Let's not kid ourselves here. I got like 1,500 Twitter followers. Weird flex. Yeah, hi, everyone. My name is Sebastian. I'm a developer advocate at Jet Brains. You're coming from the web corner, we build web storm, php storm. If you're coming from the Java corner, we're building IntelliJ. And a whole bunch of other things. Last time I counted, it was like 26 products plus. Our cloud infrastructure with continuous integration, all this kind of stuff. But yeah, I specifically focus on the Kotlin programming language, which is something that we're building at JetBrains to fit our own needs and to provide the community with a programming language. It's kind of funny how I got into JetBrains. I started doing events for them at universities and just kind of teaching people. Then at some point, I was like, well, I could continue studying or I could start doing this full time. And yeah, here we are.
Jason: Yeah. That's -- I mean, I like that path. It's kind of you're doing a thing and you can see -- you start to find something that you enjoy that you maybe were just doing -- you thought temporarily. You know what, this could be my job. What if this is just what I did? That's kind of how I feel sometimes when I realize through whatever twist of fate, I've sort of become an internet TV show host.
Sebastian: Yeah. I think it's great, right. But this is -- honestly, it's the same for me. I never thought that you could make a living like giving talks and doing tutorials for people around certain technologies. I just honestly never had that on my radar as well. I was always focused on being like, okay, I'm going to be a software engineer, write code, and that's going to be that. But yeah, twists of fate. Sometimes things go really well.
Jason: And so you focus a lot on Kotlin specifically, right?
Sebastian: Yeah, right.
Jason: So Kotlin, I think, is for a lot of us, especially in this audience, I think a lot of folks are primarily web focused. So Kotlin is one of those names I've heard but am not really familiar with like what it's used for. So could you maybe talk a little bit about what's the problem space that Kotlin came in to solve, and what got you excited about it?
Sebastian: So this is kind of interesting because the problem space Kotlin came in to solve and what it really excelled in are kind of different.
Jason: Oh, interesting.
Sebastian: So we started building Kotlin almost ten years ago now. Almost to the dot. We have a couple ten-year anniversary events coming up. We are traditionally a Java shop. So all of our 26 products, they were all built in Java. They're desktop applications, and they're huge code bases, multiple million lines of code. At some point, you kind of run into the limitations of the language and also kind of the language evolution, right. We have a lot of new trends with functional programming, immutability, concurrency, all these kind of topics. At some point, pretty much we thought, hey, we need a better language that allows us to continue working on our products that were all already written in Java but do it in a more modern style. So what Kotlin really is, or what Kotlin really started out for us was a 100% Java compatible, modern programming language which you could use general purpose. Build desktop applications, build server applications, and so on. When it really kind of took off and kind of got exponential growth was when Google, like, two or three iOs ago announced that Kotlin would be next to Java the only officially supported programming language for building Android applications. I think one year after that, they announced that Android was going Kotlin first, meaning that all their documentation, all their materials were guaranteed to have samples in Kotlin and maybe they'll also have samples in Java. But that set a very clear course, and of course that helped us with pushing adoption because once you have like really big global players like Google buy into the language, I mean, it's just -- it gives people the peace of mind it's not going to go away from one day to the next.
Jason: Yeah, for sure. And what a cool endorsement, too, when you get buy-in from a company at that scale to say, yeah, we're going to move -- how many developers get moved over to Kotlin when they make that choice. Like, that's exciting.
Sebastian: Yeah, funnily enough, traditionally -- so I'm not an Android developer at all. So I actually -- my story is kind of simple. I started writing Java code just during university. I was, I don't know, building server-side applications, all kinds of things. Then I got into this course where we were building iOS apps with Swift. After that, I kind of went back, like after all that was over, I couldn't write Java anymore. I was like, well, I've kind of tasted like this modern language. There's new stuff out there. There's better ways to do things than how we do them in Java. So I looked around. I found -- well, I found a bunch of different alternatives, but Kotlin stood out to me because it gave me the immediate premise of, hey, everything you know about Java, like everything you know about the ecosystem, it translates one-to-one over. But you get to enjoy all these cool new things and all these modern paradigms.
Jason: Nice. That's super exciting. So there's a couple questions in the chat that I think are good. So is Kotlin -- because Kotlin is Java, that means it's mostly a back-end language, right?
Sebastian: So this is kind of funny. We have a bigger vision for Kotlin. So Kotlin for us is really just a general-purpose programming language. As I said, we at JetBrains are building desktop applications with Kotlin. So all of our development environments, they're written in a mix of Java and Kotlin. Of course, we're also building server-side applications. People are building mobile applications with it. But we are also doing something called Kotlin multiplatform, which is the idea that, well, Kotlin code is compatible with Java, but it's not a Java dialect. It's its own language. We can compile it through Kotlin native. At the end of the process, X86, Apple M1 binary falls out of it. And we also have something called Kotlin/JS, which is our tool to kind of take the whole programming language and bring it either into the browser or into a Node JS environment.
Jason: Yeah, so this is actually -- this is kind of what got me excited about this. What you're proposing here is that we can use Kotlin, which started out as kind of like a dialect of Java, and now we can use that and all of the type-safety and the autocomplete and all the things that come with using, you know, the JetBrains IDEs around this stuff. We get all that in the browser for our web applications. Like we can build web applications with this type of back-end language.
Sebastian: Oh, absolutely. But we're actually -- I think we're dreaming even a little bit bigger than that. With this whole concept of Kotlin multiplatform, the idea at the end of the day is if you've written it in Kotlin, you can -- like if it's pure Kotlin, you can run it on any of the targets. Which means you can define --
Jason: Oh, interesting.
Jason: That's very cool. And is that -- so, this is a big question, but that always feels like a promise that seems too good to be true. I feel like we saw this a little bit with React Native, where they were like, oh, you can write React Native and it'll work on devices and on the web. When you actually start to see that play out, it's not as -- like, it works, but there's more finagling than you maybe want. It works for 85% of the way, then 15% is working around these inconsistencies. I'm curious, is Kotlin seeing that same challenge where when you're writing your Kotlin code and you're compiling the six different targets, are you seeing that similar kind of, ah, it worked on most of them, but we have to add this edge case in to deal with this thing?
Sebastian: Yeah, so I think there's a fundamental philosophy difference between things like React Native and Kotlin. With Kotlin, you build the same application once and then you run it everywhere. The idea is you write out your business logic once. So the things specific to your application. When you have stuff for each individual platform, you can kind of tie into that. So if you're going to be building, for example, an iOS application with kind of this whole multiplatform story in mind, you really just kind of write a framework or a library in Kotlin that abstracts away your main tasks, but your whole user interface, you build it with Swift UI or the X Code interface builder or whatever you want. You get a completely kind of native application. You can integrate natively with the camera API, maps API, whatever. But the part that's truly common that you also believe is common that doesn't depend on any platform stuff, that's the part that you can abstract away.
Jason: Got it, okay. That makes sense. Yeah, I like that. And that does really make sense to me. If you know your business logic is consistent, having it in a way that's actually shareable across platforms so you're not having to port it to -- you know, I've been in teams where we did, we had the Java library and had to write the Node version of that then the PHP version of that because we had different systems. When we had logic changes, we had to make those changes in three or four or more languages. So this is very promising.
Jason: Yeah, okay. All right. I'm in. You got me. I want to start writing some of this. So let's go ahead and switch over into the pairing view. Let's do a quick shout out to our sponsors. We've got Rachel with us today doing live captioning as we go. Whoops. What is this? Hello? You going to do the thing? Why does it think it's tomorrow?
Sebastian: Time travel.
Jason: Oh, no. Oh, no, my thingy. What have I done? Oh, god. Did I break my website? Okay, everybody. I broke my website, which means I need to do a quick search for the -- let's see. There's an iFrame we can look at so you can see the live captioning. I'm very sorry about this. Give me just one second to get this figured out. We're going to -- where's the live player? And here is the actually iFrame. Yes, I apologize. But you can still see the live captioning. It's happening right here in the window. So that is a -- oh, that's a bad link. That should still work. Even if it's not --
Sebastian: That's a funky link.
Sebastian: That's a lot of pop-ups. (Laughter) Cookie laws.
Jason: Now, we've got a whole other thing. I'm using a new IDE today. This is IntelliJ Idea, which I have used exactly long enough to -- let's see. I downloaded it. I installed some indexes, like common indexes just so it would go faster. We downloaded them ahead of time. And I believe that's all I've done inside of this.
Sebastian: Yeah, created one logic and pressed run once.
Jason: We did the hello world to make sure it would run on my computer. That's how far we got. So yeah, let's see. What can we -- use a light theme, say you have a bright idea. (Laughter)
Sebastian: I mean, if you want to, you can press shift twice. That should put up the search everywhere window. Just shift twice.
Sebastian: Then you can go for quick switch theme. I think if you type quick it's going to give you a switcher that's going to be even faster. Quick switch scheme, then you do editor color scheme, the top one. Then you can do classic light. Yeah.
Jason: Look at it go.
Sebastian: There we go. Bright idea.
Jason: We have a bright idea.
Sebastian: I love it. So by the way, before we dive in, I think someone in the chat mentioned that they actually have a Kotlin multiplatform use case in their application. I'm not sure. Unfortunately, it scrolled away by now. Someone said they were using Kotlin multiplatform. Maybe that's interesting for a couple other people.
Jason: Yeah, let me see if I can find -- I don't see it. People are talking about that it can target a bunch of different platforms, but I don't see -- somebody asked about targeting web assembly. Is that possible?
Sebastian: The short answer is we're working on it. So not quite yet, but it's another very interesting target, I think, for us. There we go. That's the comment.
Jason: Ah there. Samhamburger. I scrolled right past that one. Using multiplatform to execute a lot of shared business logic and extract away from our independent client apps. Therefore, clients are ensured to be more aligned, and future changes to this logic only need to be made in Kotlin.
Sebastian: Yeah, that's exactly what we're going for. I'm glad people are already embracing it.
Jason: All right. Well, I'm ready. Let's write line one of Kotlin here. So if I'm getting ready to start, what should I do?
Sebastian: All right. You've already set up IntelliJ IDE, which is the most important step. It's our free IDE, actually. So there's also an ultimate edition that you have running, but you can do it with the community edition just fine. Yeah, that's our development environment, which comes prebundled with the Kotlin plugin, which gives you all the things from code highlighting to completion to all kinds of fancy navigation. We're a tooling company, so this is kind of our bread and butter, to provide you with good tools. From there, we can start a new project by just going to, like, file, new project. I think we have an old JVM project open. We have Kotlin here. We can give it a title.
Jason: Let's see. So I probably want to -- this is something I can put on GitHub, right? So I can just move this around.
Sebastian: Yeah, absolutely. We even have integration for GitHub. So both for Git and GitHub in the IDE. A nice little UI. That's a bit beyond Kotlin.
Jason: Oh, it wants me to create a new one. So let's do Kotlin/JS.
Sebastian: Sounds great.
Jason: Okay. So then -- and do I name -- oh, I see how it's going to go.
Sebastian: Yeah, just give that a name. Then if we scroll down a little bit in the templates, we can start with maybe just a browser application for now. You can see we have a couple of templates. We have browser. We have React. And we have Node.JS. Also, something dropping in the next iteration is going to be compose for web, which is a really fancy way of sharing user interface code between Android and web. But again, we're getting ahead of ourselves. Let's just add a project JDK, whichever one you have installed, just to be safe.
Jason: I have two.
Sebastian: Adopt open JDK is fine.
Jason: Anything else I need to set here?
Sebastian: No. You can unfold the artifact coordinates. That's how packages are being named, but that's all prefilled. It's all good. So let's click next. And now we have -- yeah, we can just select the template again. It does not make that much difference. We could be a little fancier than usual, and we can turn on the IR compiler. That's our new compiler that's currently in alpha. I like to live dangerously, so let's do that one.
Jason: Okay, let's do it.
Sebastian: And you know what, why don't you turn on use Kotlinx.html as well. Then we can talk at length about what all of these features do.
Jason: Okay. So then finish?
Sebastian: Yeah, just finish this.
Jason: I would like to open it.
Sebastian: Yep. Sam says they would love to see ES6 support. Yeah, absolutely valid. So we're currently working on a bunch of things with the new IR compiler. One of the most exciting things, I think, is TypeScript exports. So you just get -- like you get TypeScript definitions from your application if you build them as a library for somewhere else. All right. So let's just make sure that everything works. Yeah, this indexing should hopefully not take too long.
Sebastian: Yeah, right. So when you first start your -- like when you first open a Kotlin project or generally any project in IntelliJ, it can also be a Java project, our main goal is for the next couple hours to provide you with the best experience, right, which means autocomplete, which means navigation, which means super fast search across all your documents. So what we do is we create kind of a search index. So we read the file, like your build files, which in our case is gradle. You could compare it to like web pack or any other kind of build system. From there on, we kind of create these binary representations and trees and whatnot. That honestly goes over my head. There's a couple smart engineers doing that, which is going to allow you to see code in beautiful colors. When you type a dot behind an object, it's going to show you all the methods and all the extensions and so on. So you can navigate to the source folder, if you'd like, and open -- there's probably a demo file in there. The main Kotlin. Then there's a client.kt. I think that one is prefilled. Let's have a look.
Jason: Okay. So looking at this, let's see what I can intuit. So we're importing from Kotlinx. And Kotlinx is the -- you said it was a DSL for writing type-safe HTML, right?
Jason: So in order to use different features of that, we are able to -- we have to import these. And this is kind of like --
Sebastian: Yeah, it's like a package structure. It's just kind of -- or I guess you could think of it as like name spaces, maybe.
Sebastian: So, partly, yes, partly no. Some of these features are bundled like right with the application. But if you go into your build.gradle.kts file, you can see that Kotlinx in line 15 is actually an external dependency.
Jason: Ah, oh, perfect. Okay.
Sebastian: So this one is an external dependency that we pull in from Maven or Maven Central, which is just the NPM equivalent. It's a central repository where packages live in the JVM and the Kotlin world.
Jason: Got it. That makes sense. So this one is a built in. These ones we imported from an external dependency.
Sebastian: Yeah, so if you want to -- and you actually want to see where things come from -- you're on MacOS, right? You can hold the command key and click on load. You can click on anything. That's going to send you to where that is defined.
Jason: Nice. Okay. So this is like the whole --
Sebastian: Kind of the source code.
Jason: Interface definition.
Sebastian: Exactly. So now you're kind of inside the standard library. You can even see in the top bar, it kind of tells you where you are. If you click on that again, it tell use Kotlin's standard library JS, version 1.4.32.
Sebastian: Yeah, but I mean, realistically, you're not going to write those yourself. You're just going to type things out, press enter, and the appropriate import statement is going to get added by your IDE.
Sebastian: Yeah. Oh, is that not familiar to you?
Jason: No. I mean, VS Code does that sometimes.
Sebastian: In like TypeScript and stuff?
Jason: Sometimes. I feel like it works -- you know, it's very much like an Anchorman. 60% of the time it works every time. (Laughter)
Jason: Nice, nice.
Sebastian: So same thing here.
Jason: Okay. So looking at this then, we are going to -- when the window loads, we are looking at the document.body and running a function called say hello. The function is going to append a div with the text "hello from JS." Is that a correct reading of this code?
Sebastian: The question is, where does it append to, Jason?
Jason: I'm assuming the document, right?
Sebastian: Yeah. So what you actually see here is already -- man, our code is really throwing you off the deep end. What you're seeing here is not just a basic function. A basic say hello function would just be fun say hello. What you have here is a function with a so-called receiver type. It says if I have an object of type Node, which your body would be, for example, that's a Node, then I can call say hello on that object. So you extend the functionality of Node with your own function.
Jason: And so I can't just call this on, like, whatever.sayhello. It has to be something defined. And we can already see it's unhappy with me.
Sebastian: Yeah, exactly.
Jason: And if it wasn't a Node, like if I create a local variable, it's still unhappy. Let's see what it tells me.
Sebastian: Yeah, so even if you have -- like, as long as it's not a Node.
Jason: Yeah, this is super helpful. To see this in action, if we want to run this --
Sebastian: So, okay. This is, by the way, the page your code gets embedded in. It's nothing special. It's the same as single-page applications every day. Just an empty page with a script that loads at some point.
Sebastian: So actually, for some reason, the default is browser production run. If you go to the top, there's the little elephant in the top bar. You can switch this to development run in continuous mode.
Sebastian: Then you press the little play button. Now what's happening is that the whole machinery, like, kicks into play. We have a bunch of infrastructure in the background, which abstracts away things like NPM. So it has its own yarn installation. You can run this on a system that doesn't have yarn installed. No problem. It pulls its own thing in. Pulls its own dependencies in, no problem. It has its own web pack installation and configuration. Note we did not have to write any web pack configuration, which is always a plus. I do not want to write web pack configuration. But yeah, at the end of the day, we still get -- it should pop open --
Jason: It did pop open, but it opened in my other browser. I'm going to close that one over here. Here's where we ended up. We're hello from JS.
Sebastian: Wonderful. And of course you can inspect element on that, and you can see it's exactly what we wrote, which is a div that contains a -- oh, it doesn't even.
Jason: Yeah, just plain old text.
Sebastian: So we could add a P tag in here. You can probably figure out how that might work.
Jason: So let's see what I can do here. I'm going to add a paragraph tag.
Sebastian: So one thing that you're going to benefit from is typing a little bit slower because then you're going to see what the IDE tells you.
Jason: Okay, I will stop trying to go fast here. Let's see what happens. So let's go -- I'm going to go to a P.
Sebastian: If you just type a P without any -- okay, go back once again. Here we can see it knows a bunch of things, including these nice P tags. You can click one of those.
Jason: Probably the HTML element? Seems like the one I want.
Sebastian: Yeah, that seems about right.
Jason: And I want to move this into it.
Jason: Then is this a white space sensitive language?
Sebastian: It is not. And it is the best thing ever. But if you want to have nice formatting, you can press command, option, L. That's going to auto format your code for you. Oh, it's already formatted. Nothing to do. If you want to have it in the multiline style, you can add an enter key, and if you press command, option, L again, it'll rearrange the parentheses as they're supposed to be.
Sebastian: Okay. So how about we just do a bunch of like collection stuff. So we'll create some kind of object. We'll filter it, and we'll maybe print out a nice unordered list or something in HTML. How about that?
Jason: Yeah. So I have, if we need it, all of my episodes are in a JSON file. This is the big list of 200 episodes, if we want that.
Jason: We can also get whatever.
Sebastian: Let's start by just creating a bunch of Kotlin objects first. Then we can go to that in a little bit.
Jason: Okay, cool.
Sebastian: Because I think -- yeah, there's probably some ways to do that elegantly, but let's focus on some of the language concepts before we start pulling in some other stuff.
Jason: All right. I will contain my excitement.
Sebastian: I mean, honestly, it's great that you are so excited. There's so much stuff to learn. For me, funny enough, I learned web development, or a large part of it, using Kotlin/JS. I didn't know React before I wrote Kotlin/JS. You need to bang your head against the wall a couple of times, but then you can go through the official tutorials with Kotlin/JS, and it works.
Sebastian: So -- well, I guess we can create a small data model of what could constitute some of your episodes. Why not. So let's have -- so the way we do this in Kotlin, it's classically object oriented. So we have classes. So let's create a class called episode. It starts with a capital E, as per classic. Wonderful. Now how do we define parameters? Funnily enough, when I talk to Java developers, they always kind of get the shivers because this usually means it's a hundred lines if you want to add four parameters. You add the parameters, you add constructers, a copy method. Yeah, enterprise. No. The way we can do it in Kotlin is you just open --
Jason: Somebody pull that as a sound effect. Enterprise.
Sebastian: Yeah, please do. I'd love it. Actually, regular parentheses are enough for the time being. We don't need curly braces.
Sebastian: Now we can define the properties that are supposed to be in here. Let's say it has a title. We can say val, and then we do title and then colon, and we give it a type, which is string with a capital S. That's the one. I guess we could also give it a number. So, see if you can figure that one out. Actually, the type is -- it's comma. We'll talk about why in a second.
Jason: Let's see. I don't think I have any kind of numbers. I have IDs.
Sebastian: Everything is strings these days. Everything.
Jason: I know. I have dates.
Sebastian: But who wants to work with dates?
Jason: Fair enough.
Sebastian: I mean, we're doing some stuff actually for doing multiplatform date management because we want to abstract that away. Okay. Let's assume for now --
Jason: We can just make up an ID, right?
Jason: And that's going to be a number, you said?
Sebastian: Let's make it a whole number. Int, exactly. That's the one. That's a whole class in Kotlin. That's all you need.
Jason: So we don't have to define anything?
Sebastian: No, you don't. Like this is the smallest thing that you might possibly need.
Jason: So then if I wanted to, like, create one, I call it ep. Then do I do new ep? I don't know how to write Kotlin at all, so I'm just making stuff up here.
Sebastian: Yeah, but see how it kind of looks like a function? You invoke it just like it would be a function. So val ep equals episode.
Jason: Episode. Now are you going to give me auto complete?
Sebastian: If you spell it correctly, it might.
Jason: Espisode, that'll do it. All right.
Sebastian: This is why I love statically typed languages. If something is red, I can immediately stop and say, like, what's happening? What did I break? It's never a situation of finding this out ten minutes down the line when we press the wrong button, right. I think that's lovely.
Jason: And this one, I just so happen to know, was episode 200. So we're on 201 today.
Jason: Then are these white space sensitive? Can I break these up?
Sebastian: Nothing is white space sensitive. We also have trailing commas.
Jason: I love a trailing comma.
Sebastian: So, yeah, it's all good. Actually, I find this super interesting seeing you write this for the first time with really little input. Because the names for the arguments aren't actually required. You can just write GitHub action with Octokit and 200.
Jason: Oh, look -- oh, JetBrains.
Sebastian: I'll do you one better. Press option, enter. And you can say things like put arguments on one line again. Or if you navigate your cursor on to one of the -- yeah, so you can put arguments in separate lines again, but you can also press at, enter and say add argument name or something like that. Add title equals to argument. Exactly. See? There you go.
Jason: Very nice. Whoops, what did I just do? Oh, boy. Oh, never mind.
Sebastian: You just added lazy initialization.
Jason: So what I wanted was -- yeah, this is very cool. I like that a lot. So we can kind of split that up. Separate lines, was it?
Sebastian: This is like your entry point to all the cool things in the Kotlin world or just generally in our product, the alt-enter shortcut. It's like our intellisense actions. It shows you you can everything do. So it's really useful, just kind of pressing alt-enter once in a while. Maybe you learn something new. Maybe the IDE knows something better than you do. By the way, of course navigation also works in these things. If you have episode and you're wondering where is that defined, you can click on the word episode with command, so if you go a command, click on episode, it's going to send you to line nine. It's not very far. You can also click on that episode in line nine again, and that's -- well, right now we're only using it once. If you have multiples, it's going to show you every single point.
Jason: Also, just telling you it's the only time it's used is -- like, I get a lot of anxiety in projects when I go to modify a data structure or something and I'm like, okay, so I need to find every instance of this. Just having the IDE say, hey, this is only used once, don't worry, friend. Everything is fine.
Sebastian: But don't worry because in Kotlin, you're not changing things like that anyway. For example, let's not call it episode. Let's call it -- call it podcast episode. Just add podcast to the front of this. And don't move the cursor now. You see the little R with the little pencil?
Sebastian: So this is what we call -- this is one of our refactories. You can click on this, and you can say rename. And all the instances -- and of course, it's not very impressive if you just have one instance, but if you have a thousand classes across a million files, it's going to update every single one of them. It's going to be up to date again.
Jason: That's slick. Okay. All right.
Sebastian: And by the way, even if you're getting out of this after this and never touching Kotlin/JS again, we have the same thing for TypeScript in WebStorm. This also works for TypeScript. So, yeah. Cool. So we've created our first podcast episode. Maybe we should create like -- can you add one or two more? Just so we have -- we can create a little collection out of them afterwards.
Jason: Yeah, let's just do -- oh, that doesn't do what I want. Let's do this. Then, let's see. Just count backward. So we've got one more here. That's 199. Then we've got one more with prototyping with Framer. We'll get that one in here. All right. So here's our three episodes.
Sebastian: Wonderful. By the way, I guess it's not really worth mentioning since you kind of did it intuitively, and coming from scripting language, it makes a lot of sense. Unlike Java, Kotlin has these top-level properties where you write a thing in a file and it's going to be fine. You can also add multiple classes to the same file. So yeah, for small prototyping stuff, it's amazing.
Jason: Oh, I was actually unaware you couldn't do that in Java. I'm glad that's not a rule here. (Laughter)
Sebastian: Yeah, you're not missing out. Trust me. So let's put those in a list, shall we.
Jason: Let's do it.
Sebastian: So you can create a val. Episodes, maybe. Then equals listOf. Not a capital L. Then you pass in as parameters our three episodes we have.
Jason: There's 98, 99, 200.
Sebastian: Wonderful. So now we have a bunch of episodes, right. They're all in a list. Now, the fun thing is this. We have many other modern languages. Notice how you did not have to specify this is a list of podcast episodes. You just say I want a list of these elements. So in fact, if you want to -- like, the IDE can tell you even more things about your code than what it currently does. So if you want to, we can turn that on in the IDE for a second, just to see it. If we go to the IntelliJ preferences, which is like in the top bar somewhere. You type Kotlin in the search bar. That's probably the easiest way. There's going to be -- on the left side, there's something called inlay hints, almost all the way at the bottom. Inlay hints Kotlin. Yep. Now you can click -- you can go through each category and make ticks in every single location. We will see the full power of these things. It's very funny because some of my colleagues hate it when they're IDE adds a bunch of extra information, but now you can see it inferred this is a list of podcast episodes. It knows the type.
Jason: Oh, yeah. Okay. And that is really handy. Like, I can see -- I get grumpy about TypeScript sometimes, but this part, being able to see exactly what you're doing, is very -- like, I get why people are so all in on strongly typed languages.
Sebastian: I honestly love it. By the way, a short note, probably force of habit, we do not have semicolons.
Jason: How dare I.
Jason: I'm a believer.
Sebastian: Okay, that's good to know.
Jason: I feel like I just got judged. (Laughter)
Jason: My take on it is if there's anything that has an edge case, I will just do the part that doesn't have an edge case. If you always have a semicolon, there's never an edge case. If you don't have semicolons, there are one or two edge cases. It's one less thing for me to remember. So why not just do the thing that makes me not think?
Sebastian: Fair enough. Okay. So you know what, let's go ahead and put these three things into our page, shall we?
Jason: Let's do it.
Sebastian: So we're going to write our first -- well, first of all, do you want to do just three P tags or have an unordered list? Either way is fine. We can just have -- we can just adjust the say hello function.
Jason: We already did a div and a paragraph. Let's do that unordered list.
Sebastian: Okay. Well, how do you write an unordered list in HTML? It's UL, right?
Jason: I've got my UL, HTML element. Inside I want to do a list item. That's an HTML element.
Jason: Then this part, what I want to happen here is I want some kind of logical loop. I want to say for each episode create a list item.
Sebastian: Do you believe in functional style for each?
Jason: I believe in the power of love. I'm down for whatever you're more excited about. I personally would probably do like a functional for each, but I'm on board with whatever.
Sebastian: Let's do a functional for each. So let's get into the scope of the UL.
Jason: Scope of the UL.
Sebastian: We want to repeat the LI item. Then we'll just do episodes.forEach. Click that and you get a block. That blocks get an implicitly named parameter, as you can see. This is why I love these hints, right. So now we can just -- so to add a string to this, do a plus. If you just want to have the title, that's it.
Jason: Okay. So now if I want to do the ID, I would do it.id --
Sebastian: Plus, a space, then probably -- you're going to have to -- it was statically typed, so you're going to have to call it two string on the ID.
Sebastian: Oh, my god.
Jason: Thank you for the sub, Cassidy.
Sebastian: I love you, Cassidy. Long time follower.
Jason: Did I screw something up? Wait, what's it doing? Illegal state exception. What have I done?
Sebastian: That's just because it keeps compiling in the background, I think.
Jason: This is still showing as red. Unsolved reference.
Sebastian: I can't believe I'm in the proximity of Cassidy, to be honest. Generally such a bright, bright star on my otherwise mediocre Twitter timeline. Generally.
Jason: Stop it. She's going to be insufferable later. She's just going to be strutting around. We already -- yeah. No, I'm kidding. She's the best. (Laughter) So something I've done is wrong here. I'm sure it's something simple.
Sebastian: Try to put the whole thing in parentheses. Like after the first plus.
Jason: Looks happy now.
Sebastian: Okay. So what's happening here is we have this funny thing where we're kind of -- the errors you're seeing down there is because it does the incremental compilation or the hot reloading. So it tries to do it, it fails because your code is broken.
Jason: Got it.
Sebastian: Okay. So now that works. The reason we needed to add parentheses here is because we're kind of overloading the plus operator. When you don't have parentheses it's like, well, I have a plus in front, I have a plus in the back. Like, what do you want from me? Does that make sense?
Jason: Yes. No. Maybe say that one more time.
Sebastian: All right. So what we do -- so the problem is this, right. Behind the scenes what happens here is you have some kind of builder function. You have something that builds HTML text at the end of the day.
Sebastian: And what we need to do for that is we need to kind of -- like if you just put a string in there, the programming language looks at it like, okay, here's a string. You don't want me to do anything with it. I'll just chuck it. I don't need it. So we need to do some kind of invocation. The shortest invocation we could have thought of was the unary plus operator.
Jason: So what we're doing here is we're changing the order of operation so that it puts these with precedence.
Sebastian: Yeah, we make sure. But to be fair, this is probably not the code you would want to write anyway. So go to somewhere in the middle of this. Just press alt-enter again. Ideally, this has convert to template.
Jason: Oh, that's way easier than what I just did.
Sebastian: Yep. Now you could even press alt-enter again, and it's probably going to tell you that it can remove the parentheses. Look at that. That's probably how you want to write it actually.
Jason: Yeah, that's cleaner than what I did. So yeah, this is great. This is exactly what we want. We've got an unordered list in here. It's pulling in data. All of that felt pretty straightforward. I love that it's showing these -- kind of the title and ID so I'm not having to write this code. I'm just able to know it's true. All good things here. I'm feeling pretty happy with the setup.
Jason: So before we do that, I have one quick question from the chat. When we're doing -- you said when we're putting these in, we're overloading the unary operator here.
Sebastian: You can even command click on the plus. You can see the implementation that's under it.
Jason: Oh, actually, let's do that. That's what the question was. What is happening? So we're just running the text function when we do this.
Sebastian: Exactly, yeah.
Jason: Ah, okay. So CJ, that's what's happening here. We are basically using the plus as a shortcut to call the text function.
Sebastian: And it's a unary plus so it does not receive a left-hand side. Yeah, so it just takes from argument.
Jason: Got it, got it, got it. Okay. That makes sense. I'm with it. So now let's do some operations on our object here. You said shuffle is the first one.
Sebastian: Yeah, sure. So how would you intuitively expect to be able to shuffle?
Jason: I have a theory.
Jason: Is that it?
Sebastian: That's it. Just give it a couple seconds. Isn't that amazing? Isn't that how every language should do it? I generally believe that.
Jason: I've absolutely written a lot of very convoluted shuffle code. So I'm pretty happy. Also, I think it shuffled into exactly the right order, which is pretty fun.
Sebastian: You can just reload the page on the right manually if you want to. There you go. Three elements don't really have that many permutations, do they? It's like six, right?
Jason: But so this is perfect. This is exactly what we were after. We have a shuffled list. I had to write one word that's a word I understood. That makes me feel pretty good.
Sebastian: Right? We could do the same thing for like filtering the list.
Jason: So let's do this. I'm going to start typing filter. All right. So filter.
Sebastian: Press enter again, and it's going to give you a little extra help. Look at that. You get a it. That's a podcast episode. And it asks you to provide a predicate that returns a boolean. Equals sign is enough. Yep.
Jason: Is that it? Am I done?
Sebastian: Yeah, you're done. Just give it some time to reload.
Jason: I am -- okay. Didn't realize I was going to be a Kotlin expert so fast.
Sebastian: Yeah, honestly. Isn't this the greatest thing? That's exactly how I felt when I first touched the language. I was like, I can be productive with this. Realistically, engineers who have done an object-oriented programming language with a little bit of function, they can be productive within three days. They write production apps within three days generally.
Jason: I mean, it is definitely more intuitive than I expected. I come in, I haven't written Java before, so all --
Sebastian: Now you never will.
Jason: (Laughter) Fair enough. Because I was worried when I heard that Kotlin was based on Java. I was worried about verbosity and needing to know about the standard library and a lot of contextual information. That's what you hear about when you start looking at writing Java and when you hear people talk about their issues with it. So this is a pleasant surprise, to see that I don't need to memorize a bunch of stuff, that we have the fact this is kind of solving a lot of these problems by good auto complete and good type hinting. That's really handy.
Sebastian: And I generally think one of the biggest things is just a super well-thought-out standard library. Like 95% of the use cases you can probably think of there's a standard library function for it. If you want to have a map function and it takes like an extra index, you can have that. If you want to fold, there's no problem. Even for things like, oh, I have a sorted list, I need to do a binary search on it because linear search is too fast. What do you do? You do .binary search and provide the predicate. That's it. It's weird because on the one hand, it feels magical. But on the other hand, it never is. It's just -- it just is the thing. Funnily enough, once again, you can command-click on filter because all this is just our standard library, and you can see how it's implemented. Oh, it's filter 2. So command, click on filter 2 so we can see an implementation. If the predicate is through, then we'll add it to the destination. That's how a filter works.
Sebastian: Now here's the kicker, right. If you look in line 824, you can see the inline modifier. So this means you can write functions in Kotlin that have this modifier, which means instead of being called at runtime, this code will be copy/pasted in the position of where you've originally invoked the function.
Sebastian: So even though we've written filter, what actually -- like what actually it compiles down to is just a four loop with destination where it's going to add it.
Jason: Okay. I get that.
Sebastian: This is elegant because this also means you can write your own collection operations. Like nothing is stopping you from writing your own funky filter.
Jason: So if I wanted to do something like fun inline add funk -- let's see. Let's see if I can write a function just based on inference here.
Sebastian: A lot of generic types in this one, I'll give you that.
Jason: Yeah. Okay. So --
Sebastian: So what do you want to build?
Jason: Well, I was thinking --
Sebastian: You want a function that adds funk to some string?
Jason: Yeah, I was just going to add a property that says funk. If I wanted a generic type -- which I assume I can use this one.
Sebastian: This one is actually for -- actually, this one is too complicated. You can just say iterable T.
Jason: Like that?
Sebastian: Almost. So without the outer brackets. What are those called?
Jason: We call them pointy boys in here.
Sebastian: What do you call them?
Jason: Pointy boys.
Sebastian: We have pointy boys, curly boys.
Jason: And round boys.
Sebastian: What are the square ones?
Jason: Square boys.
Sebastian: Oh, okay. Bracky boys. So first of all, to help the IDE along a little bit, you need to change the order. It's inline fun, not fun inline.
Jason: Oh, got it. And that's what we're having, inline fun.
Sebastian: Exactly. And one more thing you need to do is you need to once again -- this is kind of goofy, but you need to tell it the generic type parameter once more. So you need to say inline fun brackets -- sorry, pointy boys, T.
Jason: Like that?
Sebastian: Yep, like that. Now you have a function called add funk.
Jason: Okay. Looking at my collections here, I get --
Sebastian: So keep in mind right now you are writing an extension function. So this is something you can call on something else, which means you already have an implicit parameter. This, which is like what you call it on. Does that make sense?
Jason: I already have a this, so I don't need anything. I can just do like a this.funk equals true.
Sebastian: Yeah. Now we just need to somehow -- well, first of all, need a couple parentheses there. No biggy. Round boys. But now you have -- well, we're a statically typed language.
Jason: Right. So I need to add to I episode type.
Sebastian: Yeah, but we can go one further. We can create an interface. We can create an interface funky. Then we'll just define this. Just so interface funky. And that one provides a var funk. So not val but var. Now we want to be able to write to it. And you say colon boolean. So anything that implemented this interface needs to provide a funk variable, which is a boolean. Now the next step is probably that we want to say, okay, instead of on a generic parameter -- someone wants to make it it IFunky. So instead of a T, this is just funky. Now we don't even need this one anymore.
Jason: Oh, perfect. Okay.
Sebastian: And now we are confused because we don't know why that doesn't work. Give me a second here. Oh, yeah. You still have an iterable. So you have a list of funkies now. So you want to do this for each of your elements.
Jason: Got it, yeah. For each.
Sebastian: Yeah, look at you. You're a natural.
Jason: Okay, all right. And this -- so now I get my -- I get to add my funk. But we have a problem, which is that my episodes don't implement the funky interface.
Jason: Can we make it -- is it going to break if I say implement funky? These would be invalid then, right? Because they don't have the required property.
Sebastian: Well, let's take it one step at a time. What did we want to do? We want to have the podcast implement funky. So let's go to the podcast episode.
Jason: Does order of declaration matter?
Sebastian: No, fortunately it doesn't. That's one of the beautiful things.
Jason: No, that's wrong.
Sebastian: So what you do is at the very end of the line do colon funky. So both inheritance and --
Jason: Now it's mad.
Sebastian: What's the other thing called? Composition. So both inheriting and implementing interfaces works with a colon in Kotlin. Still same rules apply. You can inherent only from one thing.
Jason: So now you're happy.
Sebastian: What's the problem with this one? Hover over this. It hides et member of the type funky. For all you know, you may have already had funk in here. But it may have meant something completely different. So now you got to make it explicit. The funk you mean here comes from your interface. You do that by adding the override modifier. I think it gives you the little link if you just press add override modifier.
Jason: So, okay. I do command-shift-enter.
Sebastian: Either click the blue link or once again do that.
Jason: That's cool.
Sebastian: And it shows you the next thing. Oh, it's a val property. But we said we want to be able to change this. So it needs to be a var property. So we change it to var.
Jason: Basically, you option-shift-enter your way to victory is what I'm seeing here.
Sebastian: Kind of. Now all this code is red. See all the brackets that are red, and in the right side bar you see the three red icons? Why is that? Well, you didn't pass the parameter. But we're not going to pass that every single time because by default, nothing is funky. So we can provide a default parameter. So you just do that by saying equals false.
Jason: Okay, all right. So let's expand this so we can see what's happening here.
Sebastian: By the way, you can once again just press alt-enter and say put arguments in separate lines, I believe. Yep. That makes it a little bit more narrow.
Jason: Much easier to read. So now, yeah, we've got our title, ID, funk.
Sebastian: And funk.
Jason: You are not funky by default. It implements the interface of funky. And now we can put these together safely.
Jason: This is also very nice that it does this.
Sebastian: Type checker says it's all good, man.
Jason: So we save it.
Sebastian: First of all, we want to make sure this is actually the thing. We want to be able to print the funkiness. Probably want to add that to the list.
Jason: So let's add funk. Got a problem.
Jason: Two string? Or does it two string itself?
Sebastian: If you have it inside one of these fancy templates, it's going to two string itself. It needs to be it.
Jason: Oh, yeah.
Sebastian: And not is. Also, we forgot a thing. Right now we have a call chain, but we're trying to add funk. That doesn't return anything, right. That probably wants to return the same iterable again.
Jason: Like that?
Sebastian: Wow. Okay. I think we're going to run into some funky generics in a second. We'll see. Now we just need to return this again. So just say return this. Return, yep. Now it's still broken. Why is it still broken?
Jason: Great question.
Sebastian: If we scroll down, we'll see that, well, what did we get back? We get something back that just implements the funky interface. At this point, we have lost the information that we're still episodes. Because all we say is we only return something that has a property called funk. Okay. That works.
Jason: You going to do the thing? It doesn't like that. Unresolved reference. Oh, because I'm just wrong. That's just me being bad at this. Okay. I don't see any errors anymore.
Sebastian: Yeah, this is looking good. Give it a moment to think about it.
Jason: Okay. So that did what we want. Now I want an if statement. So if it ID is 199, we'll do it funk equals false. I'm making some assumptions here.
Sebastian: It's all good. You see this tiny little shadow in the background?
Jason: Yep. Redundant if statement. What does that mean? Redundant if statement. Let's hit the button and see what happens. What?
Sebastian: Yeah. We understand your code probably better than you do.
Jason: Clearly. All right. So then I'm going to drop this filter. Instead, what we should see is that we should see true, false, true here if we do that.
Sebastian: So one of the things we're also working on with the new compiler, by the way, is speeding up the iteration speed or this recompilation speed, which is going to take a bit.
Jason: Look at it go.
Sebastian: Poor episode 199, not funky.
Jason: Well, that was one where it was just me by myself. There's zero chance that was going to be funky.
Sebastian: I see. Actually, question as someone who's not a native English speaker. Is funky generally a good connotation or bad? I know something can smell funky. That's usually not a good thing. But I think generally, like, if music is funky, that's pretty good, right?
Jason: Yeah, I think it's like funky dances is really what we're thinking about here.
Sebastian: Okay. That sounds great. That's what I had in my mind as well. Cool. Yeah. So I think we've had a -- one question in the chat, which was about immutability. They were asking if I have -- I don't like vars. I just like vals. The answer to that is we have a fancy function. If you go up to your podcast episode again and you annotate this class with the data keyword, so call it data class. Just the very beginning. Then we go back into our main -- sorry, our funky loop. We can rewrite this to be -- actually, let's also make sure that the funky interface is now val. We're going to rewrite this into immutability. Does that make sense?
Jason: Yeah, let's do it.
Sebastian: Okay. So at this point -- oh, I'm sorry, you need to change it into a val up there as well. Exactly.
Jason: Can I take out the default?
Sebastian: You can, but you don't -- I'm not sure if we want to. Let's keep it in there for now. Okay. So let's go back to the little red squiggly that you can see in the right scroll bar. Exactly. Now it says, well, we can't assign -- we can't reassign val. So now we're immutable. That means we need to switch to a map. That makes sense. Now we need to create copies. Good. Good moves. Look at you.
Jason: But I'm still wrong.
Sebastian: So we get a podcast episode. Just type "it" inside. So we want to create a copy. We say .copy. And copy takes a bunch of arguments, all of which are optional. We can use named arguments. We can just say funk equals. Then we put that argument in there.
Jason: Oh, yeah, we want this one, though.
Sebastian: Exactly. Boom. Just like that.
Jason: Now it's happy again.
Sebastian: And I can do you one better.
Sebastian: You see how our whole function is just one statement? Go on the return. Press alt-enter. Convert to expression body. Press the delete key once. And now -- well, it's still a bit wide. Now you can see instead of writing a body for the function, right, we're just saying this function is this expression that follows.
Jason: Oh, interesting.
Jason: That's slick. Okay. I get it. That's really nice. So this is like a shorthand function to get mapping in my head.
Sebastian: Right. So whenever you have a function that's only a single statement, which often you do because often you're just aliasing things or wiring up parameters or whatever. You can just say that function and then equals the other statement that it represents. You don't even need to do the whole body return shenanigan. You can see see that it infers the type again. So the list of podcast episodes it still says there.
Jason: Yeah, yeah, yeah.
Sebastian: Again, some people don't like this because it generates a lot of text, right, but I love it. This always gives me the confidence that my IDE understands what I'm doing.
Jason: I would agree. I think seeing -- like seeing what you have passed in -- because at the end of the day, no matter how much we all think that we're geniuses, computers are going to understand the code better than we do. They interpret it. So having the computer tell you what you actually did, this is going to save me a lot of heartache. I feel like many of the bugs I've spent the most time on aren't obvious bugs. They're bugs where I was one level higher or lower in the scope where I needed to be. I thought I was doing one thing and I was actually operating on the original type, not the modified type, or something like that. So this is definitely the sort of thing that can help me kind of save me from myself a little bit here.
Sebastian: Yeah, no, absolutely. At the end of the day, it's also not only that the compiler or that the computer understands our programs better, it's the interpretation of the computer that is the one that matters, right. If we mean one thing and the computer understands another, it's just going to explode. We don't really have a say in it. So me seeing kind of the compiler as a co-pilot who constantly tells me, okay, now you're in the scope, now you have this kind of thing, and by the way, after we turned this on, I'm not sure if you actually noticed, but you can see the implicit scopes of our domain-specific language. You can see that if we are inside a P tag, for example, that you have an implicit this which is a P. If you're in a div, you have a this that's a div. These also define the functions that you would be allowed to call. Like on a P, you can't add an H ref because that doesn't make sense.
Jason: That's pretty slick. All right. So we have about ten minutes left. Is there anything you want to make sure we cover before we start doing links and all that good stuff?
Sebastian: That's a good question. Let me think for a second. Um, I mean, we can open a React project with Kotlin/JS for a moment and just look at the default of what that generates.
Jason: Yeah, let's do it. So I'm going to save this.
Sebastian: Don't worry, by the way. IntelliJ always auto saves for you constantly. And now of course the question is like, but what if I made a mistake. You also have something called local history, which is like a Git history, but it's all the changes you made over the last hour. Even if you didn't check them in. That also saves a lot of butts, let me tell you.
Jason: That's really nice. Okay. So I've created a project called Kotlin/JS React. I'm choosing React application, the same JDK as before.
Sebastian: All good.
Jason: I'm going to save that, then we'll go here.
Sebastian: Take whatever you want.
Jason: I'm going to skip all these because we aren't really building anything. So let's finish and open a new window. All right. So inside here we have -- and you see here where it's doing the gradle build, that's the stuff I was talking about earlier. This is all happening in the background. So we've got our client.kt. So we get into render, document, and window. We get the element by root, class, Kotlin/JS. Let's look at React. So in here, we've got React builder component, prop, state, div and input. All right. So we're specifying welcome props. This is like prop types.
Jason: Then we've got state, our state. Okay. JS export is so we can do an export as a named class of welcome. So I can import welcome from whatever?
Jason: Okay. I've got my init. We're going to drop in the welcome state with the props, which come in from here.
Sebastian: Comes from the argument, exactly.
Jason: Then we're going to override, because this implements the component interface. All right. Then we use the render function. The render function is going to return a div with an input, some values, on change. Okay. I get it. I follow this.
Sebastian: And you can kind of see, again, it's React, right. So again, in the div, we have a hello. We reference directly the state.name. We don't do any kind of funky binding or whatever. It's all reactive from the get go. So if you stop the development server in the other project, you can kick off this one. Yeah, either is fine. That's the trade-off between file size and compilation speed. By the way, I just realized that this is all class-based components, which I'm not sure how you feel about those. We also have support for hooks.
Jason: Excellent. I was going to ask. Unfortunately, we don't have time. So this could potentially be a follow-up episode, to do some React in Kotlin/JS. I think that could be fun. So let me reload this. There it is.
Sebastian: I think we also should do an episode on WebStorm, thinking about it. It seems like there's a lot of stuff people could learn from just getting to know the development environment a little better.
Jason: Absolutely, yeah.
Sebastian: Even if they're TypeScript.
Jason: Yeah, this is great. I think there's some -- there's a lot of potential in this. I can see the benefits of the type-safety. I can see the benefits of how this would -- you know, once you get the hang of the syntax, this feels like a pretty well-defined way to go about this. So I definitely see the appeal. I'm going to say I'm cautiously sold on this. I think it's a good thing to kind of dig into. So for somebody who wants to take this to the next level, they want to dig in further, where would you recommend somebody goes? If they want to learn more about Kotlin and Kotlin/JS.
Sebastian: So I think a great entry point, first of all -- well, it's just Kotlinlang.org. That's where the whole story starts. One link which I think we should make about ten times bigger and in like Comic Sans white on red background or something is the play button on the top right. So if you click on that one, first of all, you get an IDE right in your web browser so you can start typing right away, which is an absolute masterpiece. Unfortunately, you don't get as much of assistance as you get in the local IDE. But you can do that. It is going to work, hopefully. Yeah.
Sebastian: But more important are the other three tabs we have at the top there. So I usually recommend people who have programming experience to start with our Koans at the very right. These are kind of small, self-contained samples/challenges that each introduce a single Kotlin concept. Anything from classes to functions to extending to scope to whatever. So you can go through these. I think you can also save your progress as you go through them. You can kind of get an overview.
Sebastian: So it gives you a small challenge, tells you where to look in the docs and you can go from there.
Sebastian: If you are a beginner programmer, then I would recommend the book "Atomic Kotlin," which was written by one of my colleagues. I think the first couple of chapters may be also free online. I'm not sure.
Jason: There it is. Okay.
Sebastian: Yeah, this is the one. Exactly.
Jason: All right.
Sebastian: And apart from that, if you want to dive deeper into things, on play.Kotlinlang.org, we have the hands-on labs, which is one of the other tabs. You can find things like building web applications with react and Kotlin/JS. Or creating HTTP APIs. All kinds of things. Not just Kotlin/JS but Kotlin all over the place. I think there's some stuff on mobile there as well. A bunch of different topics.
Jason: Yeah, great.
Sebastian: Apart from that, I think the only thing our marketing department would kill me if I didn't shout it out is you can go to YouTube.com/Kotlin, which is our YouTube channel we started like four months ago, five months ago. If you have not seen enough of my face yet, I'm there on like 20 different videos at least. And we have videos about the recent updates, but we also -- I actually have a show called Standard Library Safari where I take people through each kind of subsection of the standard library. We talk about list, maps, sets, and all the cool stuff that you might not know from other languages. So really diving deeper into this.
Jason: Nice. Very cool. All right. So with that, everyone, make sure you go follow -- yeah, check it out on YouTube. Go follow Sebastian on Twitter. And remember, you have been able to follow along -- let's see. Where are the -- oh, no. I lost the captions again. I'm not going to look that up again. The captions have been with us. I apologize for breaking the website. We've had Rachel with us all day from White Coat Captioning. That is made possible by Netlify, Fauna, Auth0, and Hasura, who are all kicking in to make the show more accessible. While you're checking out the site, look at the schedule. We have some good stuff coming up. Rob Sutter will show us some cool things in Fauna. Then we're going to have Mark Erikson here to talk about Modern Redux, which he says is a big leap forward from if you wrote Redux years ago. The difference is stark. I haven't seen it yet. Really looking forward to checking it out. We have even more coming up. I have a bunch I need to get up on the website that I haven't done yet. Maybe I'll fix the website and update the schedule all at the same time. You can always get new updates by clicking this add on Google calendar button. I'd like to have you click that. It is fun. You can also follow on Twitch to get notified when we go live. Smash that like button and ring that bell. Okay, thanks, y'all. With that, we're going to go find somebody to raid. Thank you so much for hanging out. Thank you, Sebi, for teaching us today. We'll see you all next time.
Sebastian: See you, everyone.