Kotlin 102 - Beyond the basics by Hadi Hariri

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so this isn't advanced that's why it's not called call in advance it's call in a little bit modern basics but we'll try to cover a couple bunch of things how many of you using an introduction just play with it and write okay right on so I'll go through a bunch of different things we'll look at some things around the higher-order functions BSS how to create dsl extension functions generics how they differ a little bit from java inlining where inlining is useful we'll look a little bit at co-routines sequences for lazy evaluation and a couple of other features that have been brought in 1.1 that's a lot we'll try and get through them as much as possible also I've given we're running late with sessions a little bit so I'll try and speed up okay if you have any questions feel free to just keep them to yourself don't ask me joking obviously interrupt me and ask me any time and the way we go so we'll start with the DSL stuff and if there's I'll go through some things quite quite fast if if you honestly if you do have something that you don't understand just just taught me right with this maybe you know some most of the things I'm guessing that you're familiar with so you're all familiar with the concept of higher-order functions right where it's a function that takes a function of function returns a function and just to get familiar again with the syntax of Oh Kotlin so here I declare a function of higher-order that takes a parameter of type string and then it takes another function that takes a string and returns a string and I'm executing the operation by just calling up and a value that's passed in right so here I have the similar sin here I just have a lowercase ignore that well this is the function that matches the signature up here so it takes a single parameter and returns a string to call it I just do higher-order hello and in this case I'm passing in the function name by reference obviously here I could also pass in a lambda expression so you know I could say eggs eggs plus whatever I could also just use the it reference when there's a single parameter in a in a function I can just use it and not have to explicitly refer to the parameter when I'm declaring the lambda okay everyone's good with that right if I don't hear a no I will assume everyone's good with that right good so you don't have to constantly say yes Heidi we're good move on what are you Swedish you know Swedish people are very very quiet are there any Swedish here no very quiet only we only beat them by the finish we're more quiet anyway all some people but very quiet and talks right so we've taken this higher-order functions we've got a lot of higher-order functions built into the standard library and Kotlin you've seen some of them like width which is part of the Santa continent that takes a function block with a given receiver as its receiver and returns a result there's another one that quite often used which is let which allows you to use a object inside that scope without having to declare it externally so a bunch of these are built in and you can also create your own so here's an example of me creating a using statement right if you're familiar with c-sharp I have the using which is kind of similar to try with resources I do something and then I something that has to be disposable something that has to be closeable I do something with it and then free the memory right so I could create that same kind of structure in Kotlin by you by creating a top-level function that is a higher-order function that takes a closer Ballabh jecht and then it does something with it with the with the code that's being passed in and then closes that object given the fact that Kotlin allows me to have a lambda or multiple lines it gives it this kind of like little structure in a sense right so this really kind of looks like a keyword of the language but it's not a keyword it's just a function that I've declared okay now with extension functions one of the key aspects of Kotlin we if you're not familiar again very very simple concept is I can extend any class via the Java class or a codling class with new functionality so here I have a string to title case and what I'm doing is basically extending the class string with a new function which is to title case ok and returning the value and then you can have you know take that so for example func string is is the same as for instance and then I pass in a value here value string and then I can say this equals value right single line you don't need to open up curly braces and all of that this is referencing the instance of that class that object that I'm creating an instance of for class I'm creating instance of so this allows me to do something like this hello is the same as hello right and you can make this even a little bit more nice and say hello is the same as hello right now that gives you an error but this is what I call IntelliJ driven development which is essentially fix that for me and it just adds an infix modifier to that function right so functions that allow you to have function extension functions of member functions that have a single parameter can be called an infix notation by prefixing it within fix and you can still call it in the same way as you can see up here okay now i'm showing you all of these because we're going to eventually combine them there's another thing that you can do in Kotlin which is operator called invoke in Kotlin difference to scala you can't create an operator out of every symbol and its mother here you can only create operators or over overload override operators that we do a series of conventions that we have so one of them is the invoke operator which essentially means that I can now create an instance of a class in this case foo and then invoke that object passing in some practice okay now all of these are very similar to concepts that you have in other languages but one thing that is unique to Kotlin to date is this concept of lambdas with receivers and we call them lambdas with receivers because we kind of create invented them some times they were also called like higher-order extension functions but I think we're settling on the names anders with receiver essentially this is a higher-order function as you can see here right but what this is is a higher-order function that doesn't take a normal function it takes an extension function okay so that means that when I pass in this lambda this is an extension function to route handler meaning that I have access to everything that the route Handler provides me okay so you'd say why do you want to do that well because it looks cool I'm joking here is why you want to do something like that okay let's scroll this up here I have a class request and a class response write the request class has a method property a query property and a Content ID the response has a content and a status code right now I have this class route handler that ignore this I mean this is not even relevant to it I'm just giving you an example it can have any code there that takes a request and we sorry has a request property and has a response property now I declare a function that's called a route handler that takes an extension function of the route handler class and then all it does is just return that function okay so I can now do something like Ruth handler and this is a lambda expression right if we do route handler here you see that the ID gives me the completion directly there this is what we're expecting we're expecting here a function right in Colleen like groovy if the last parameter to a function is another function you can just drop it and go outside right but here's the key thing this isn't an ordinary function it's an extension function which means that I have access to all of the properties of that class and I'm extending so I have requests and then from here I have content type etc so why did we do this this is how you can create those dsls right this is how kobold has created a dsl for building this is how you can create if you've ever seen the groovy HTML builders that's also part of this way of creating DSO okay so it allows you to create nice-looking DSL and of course I can you know I can extend this with other things I can say request request content type and then inside the request have a response and then inside the response have like status code equals 100 right this one is that would need to be a bar but this it says oh let me create a member function you see you can even have do this or without even knowing what you're doing like me and go back to where I was right so well you get the good so what I just showed you is it's using that invoke that I just talked about to allow you to combine these and create this kind of dsl flow okay if you look up HTML builders culinary ml builders you can see that we have this Kotlin HTML builders this is the type safe groovy builder so you can see that all of this code here is basically HTML but it's all statically typed each of these are functions properties of classes etc and as I said Gradle does this cobalt does this all of these have created their different yourselves there's another project called tornado tornado effects which is a wrapper a DSL around it's actually not only DSL it's like an application framework for java effects so you can create your views using a DSL that tornado defines as opposed to using XML or actually decoratively creating all of the different objects ok so you can see that here I have with moved sent to the table view have a field set a field etc and all of this is translating obviously down to Java effects under the covers right it's all inter art so it's just calling it's not reinventing anything it's just calling all of creating one of those Java text controls itself any questions no nothing okay are you still following me no nothing okay do you want to leave well I would say go out early for lunch but the lunch here isn't that great anyway so at least them that's it's always it's got it um common with a so just a box how many of you have been to democracy Belgium so you know that it's got Fame for not having the best lunches to the point that they actually create their own videos saying how bad our lunches are at devoxx no I'm not saying it they are okay No so inlining now in the higher-order functions when you pass in another function what is what's going to happen is that it's going to you know it's creating a call stack right so you might question like how does this impact the performance you know what is the what what happens here when I have a lot of functions and you know I want to all of these are being passed in and it's creating in India targeting Java 6 is creating anonymous classes and you know this might have performance issue what you can do is inline some of these higher-order functions right in line which basically means copy paste the code anywhere that function is called right and if you look at the standard library a lot of the functions that are part of the standard library are inline ok so if I come here and I say inline right what this is doing is now in lining this so every time this operation is called it's going to inline the code along with the function that it is being passed in now of course this means that every time I do this it's going to copy paste that code everywhere in my code base right essentially I mean but you know once it trying to compose to Michael so you've got to you know see whether it's worth it you know if I'm having very long methods that is it really worth for me to do that it only makes sense to inline functions that are high order functions because otherwise it really doesn't make sense in fact if I were to do something like inline here it would say you know expected performance impact of inlining is negligent it's insignificant it's it's of no use so why would you want to do something like that sometimes you have multiple parameters that you're passing in multiple higher-order functions and multiple functions that you're passing in and maybe at times you don't want to inline a certain call for Interop reasons or whatever and you have this no inline directive right so if I have multiple lambdas one of them I can say sorry multiple functions one of them I can say don't inline that now I've added a knowing line here with a single function being passed in and I've got this inline directive so again it's going back to what are you doing right you're saying to me - inline but the only thing that I want to inline is our function so what's the point of that if you've just told me to not have that knowingly now this gives way to a bunch of different things that we're going to take a look at and in particular returns which affects the behavior okay so let me ask you a question here is a function that says containing function numbers 1 to 100 then it says go through them and when you find someone that's dividable by 5 return if I run this what do you think the output of that would be so if I come here and say containing function what do you think the output of that would be 1 2 3 4 okay what else what will it print hello or any snuffing nothing so let's see what it does we'll run this and it doesn't print anything okay who expected it to print return print hello anyone right that's a non-local return because what it's actually doing inside the lambda it's returning outside of the containing function okay now you can change this behavior now let's say this example okay instead of using for each I'm going to do my for each right and I'm going to write a print line hello here what's the result of this if I were to uncomment this line what would the result be hello no compiler error right and that's because return isn't allowed here because this only works for functions that are in line okay so if I inline my for each then it works because it makes sense right it's inlining and the return is acting on that code that was copy pasted and it's going out right so what happens when I want to actually print hello how do I do that right what you can do is you can say to return at the lambda in this case the lambda is the for each so I say we turn at for each so in this case what it's doing is a local return it's coming back outside of this lambda so when I actually right here return you can see that completion provides me with the ability to do it at for each because the function is called for each if it was called Jo we would do return it Jo right so if we go to containing function 3 and run this you see that it does print hello okay now you can use the label as the name of the function or you can even define your own kind of labels right so here I'm giving this lambda label and I'm saying it's returned pouring the label I'm saying my label and then I get completion to my label okay now what yes go ahead invert yes all okay I see I don't think so I think that there's reasons behind that that it wasn't initially done no it just comes out comes out so it's returning outside of this lambda don't say that word don't say that word containing function five what do you think that does okay now you'll like her head this is why let's see what it does print hello because this is not a lambda this is well it's a lambda because lambda is anonymous function but is the anonymous function it's not a time this anonymous function so you can see that there's an actual function here okay so if you don't want to use labels and you want to pass in you know you don't want to explicitly call that function you can just create anonymous functions which is a different way to create anonymous functions so that's one aspect that inlining also it impacts the other one is for in terms of type erasure so from those for those of us that came from the dotnet the JVM is this horrendously horrible place where what do you mean I can't query on my types at runtime on my generator you know when I have generics and want to see the type well JVM suffers from type erasure suffers it's the architectural choice for for the benefits that it has with Colleen we also have we inherit that type of Asia but when you have inline functions you can add the really fight really fight to it to then get some information about that type of runtime so here I have an inline function and notice that this is giving me it again not warning it's saying there is no expected improvement remember I said the only reason you want to do an inlining is because if you're passing on a lambda I lied sometimes you want to do that when you want to use reification okay so here I can't say if input is of type T because it says cannot check for instance of a race type however if I say that this is reified I can now do that and that warning also goes away because it understands that the reason I'm doing this is to try and get information at run time okay so there are certain cases where you will be able to use this reified to be able to query information at run time here's another type right I print line the type otherwise I wouldn't have that information and adding reified allows me to get that okay now another aspect of Kotlin is delegation how many of you use delegates in Collin okay so delegation is basically essentially you can do delegation of functions so one class delegates functionality to another class in a typical scenario what you're doing is you know you've got the concept of dependency injection where you have a class that's passing in another class and then it's delegating that functionality to that class we kind of build that into the first-class delegation where you can just say it's the class the functionality is delegated by some other class and you don't have to have that private field which there is unfilled in call in property private property too an instance of that object right basically composition but you also have delegation of properties so I can create some code that I can reuse over and over again in different places and have the implementation a single time and properties using that implementation so here I have a delicate and and the car and the standard library again ships with a bunch of out-of-the-box delegates right there's a lazy delegate so here you can see that I have a lazy property so what this is going to do is a lazy evaluation it will lazily evaluate when the first time that property is accessed and I'm saying evaluate it using you know run the function in it late and this is going to be run and you can set the threading model here so this is built-in if you go to lady you can see that it allows it uses a synchronized synchronization to say if you know do you need any kind of locking on it and this is built-in the other one that's built in was this bunch built in but another one that's built in is called V towable right there's an observable one built-in that fires off something every time the value changes and then there's V table which basically says if a certain condition is met then change the value if it isn't don't so here I have a lambda that the syntax of veto wall is an old property that sorry the name of the property the old value the new value so I say if the new value starts with s then change it if not don't so if I run this you can see that string string strange because it was string I set it to change it doesn't start with s so it still prints out string I then change it to strange and then it sets the value right so there's a bunch of of delegates built in that you can take a look at and see all of the different ones that are built in ok observable veto or not now let cetera now I think that property delegation if you want to go one step further you can also create your own delegated properties right not just use the lady in all of that and so here I have a class service that has a property delegated property string and I'm saying delegate that to a custom delegate right now what this basically means is that I have to create a class it's not an interface I have to create a class that implements two operators get value and set value okay that the class has to have this signature and then here again I have the property and I can you know access the values type the name of the property and if I need to have a backing field then I can just create a private property to have that back in field etc okay so you can use the built-in ones which probably for the majority of cases works and if you want something a little bit more advanced you can just create your own delegated property okay now let's go to uh actually I'm that means leave this one to last let's go and see some quick things so how many of you do look Haskell right so you're aware of like type aliases in Haskell so this is not the same thing because you're going to ask so I'm going to be something it's not the new type it's basically a being it's basically an alias literally an alias like when you go to the command line what you can do is you can say a type I've created a new type and it's actually an alias for another one so here I have customer name so I say customer name is an alias for string meaning that now when I declare my data classes I can just say name is a customer name right at run time it's a string when in composite it's all string it hasn't created any new type it's just a string but it does provide you with a little bit more semantic meaning sometimes I just want to reuse the same thing over and over again and give it a better meaning and I don't have to create a class which is essentially has a property of that value it's a very simple example of when to use it let's go to sequences so here if I run this right you've all seen things like that in colon which is an array of numbers and then I go elements filter it everything that's lower than 30 and then map that to a pair for instance this is going to go through the entire list it's going to go through the entire list and it's going to print out the ones that are less than 30 what do I how can I do lazy evaluation I can just add the ad sequence so now what's going to happen is that it's going to lazily evaluate this so it's not going to go once it hits that 30 well in this case it will because it doesn't know that you know that it's going to be 31 next or whatever but it's essentially doing a lazy evaluation from this point on right so essentially a lot of times what you can do is take any collection and then just do a sequence and then it will convert it if you want to do something a little bit more complicated you can just write generate sequence and then that takes a lambda and from there create your own mechanism to do lazy generation so to speak initially this was called streams but then Java 8 came out with streams so we decided to rename it to sequences okay now variance and covariance and contravariance and all of that wonderful thing how many of you familiar with variance and covariance and contravariance and okay so essentially you've used a super extends question mark all of that horrible things yes so we Colleen has covariance and contravariance for generic types it's different from Java in that in Kotlin its declaration site not use sight which makes it a little bit nicer to use because you just declare it once not every time you use it okay what does that mean so here first of all this is invariant right why doesn't this work okay because I have it I have elements which is a mutable list of any object and then I have strings which is a mutable list of string and then I say element equals string right in principle logically you would say well string is a subtype of any so in principle this should work the problem is that it doesn't because this is mutable so you cannot guarantee that you can essentially add a string to it or add it in or add whatever right in order to be able to if it if it were then it would be covariance speak right but in order to do that you need to have some sort of guarantee that it is that I'm only going to be able to like producing or consuming from here am i generating my reading and my writing so in call them what you can do is this this specific one is covariance because it's list and the difference between list and usable list is that the list is immutable right so in this case it is immutable now if we go to list you see that it has the declaration out II okay which is that's what the declaration sight variance is about it's saying that this one is only going to be producing values right it's not going to change so it's fine in fact and again the IDE helps you here because let's say that I create a class something which is of type generic and I go ahead and create a function that says generate something some things and that's going to create a list of T okay and just add this okay you see get the little squiggly because it says well in principle this can have out variance right because you're not modifying anything it's an immunity it's an immutable list so I can add that now let me go ahead and do fun like so example consume something and I take a list of T it no longer offers me that option right the opposite of covariance is contravariance which is represented in column with in some sort of outfits in and it's saying that well this doesn't work but now that does work which is consuming now there are cases where you want to be able to there are cases where you want to be able to declare something as the variance or contravariance but you can't do it as part of the declaration essentially doing a use site and Colleen also does support that but generally the way that you work with their covariance and contravariance is Konnan Kotlin is using the declaration side which makes it much nicer because every time you use again you don't get all of that noise of the super extends I can't even remember that I don't write Java so please excuse my really really crappy Java okay so last thing we're going to look at today are Co routines so how many of you have played with the co routines okay how many of you are familiar with co-routines think of them very simply put AZ or lightweight threat kind of right so let me show you a typical simple quality now the idea behind co-routines is a you know how what do we do to bring a synchronous programming to cotton and very early on the Andre team made the decision that they're not going to build in building anything specifically into the language in the sense that they're not going to do something like what c-sharp it which was a sinker weight right so sous-chef has this in Kuwait and then JavaScript has kind of there's a JavaScript library that kind of copies the same concept of a single weight so essentially in c-sharp you would do you would have a function that is a sink declare the sink boy or you know in blah blah right and then when you were calling that you would say a weight x equals blah blah right why don't I get completion here there you go did you know that you can get text completion while you do because I showed in my tech tips and tricks if that's called hippy completion for a write B I get blah blah without that right we don't build that in so there's multiple options you can use you know Rx how many of you use rx which is fantastic the promises future's all of these different things what we did is implement generic co-routines suspended all computations and there's actually only a single keyword in Kotlin which is called suspend all right that's the only thing that's been added to to call it all of the other functionality that co-routines provides in Kotlin is actually part of a library and it's not even part of the standard library it is part of a library called Kotlin X so that's why I'm importing here it's called Linux right so if you come here and say called Linux that it's got multiple things that's got Colin XHTML etc and one of them is co-routines ok so here what I'm doing is I'm launching co-routines right and we'll get to the common pool and all of that in a minute and the first thing I'm doing is I'm delaying 1000 seconds and then I'm going to say print line world and then continue down here and say print line hello and thread sleet mm right first let's get rid of that and if you rerun this the result is going to be hello why because it's launched this co-routine this lightweight thread and it's immediately continued from here it's printed hello this co-routine didn't have time to complete because it was on a delay of 1000 right so that's why you only get hello so in order to actually see the result I'm going to add that thread sleep at the bottom so that the main thread can sleep so that you can see the result right so now you see hello world okay now this is not the clean you don't want to be having these things in your code base right you're not going to be having so it sleeps in in places the proper way to do this is saying that you're returning a run blocking or wrapping this and what's called the run blocking so run blocking is a function that takes some code and then runs that code and is basically waiting until that co-routine finishes and put dumps it back on the main straight right so essentially what I've done is remove that a thread sleep right but I've wrapped this in run blocking so my main is now part of run blocking and by default this is returning a unit which is boy which is nothing so if I run this now will also see hello world right okay so that's what the run blocking is and you're going to see that quite a bit now I told you that this is lightweight thread let's do a thread comparison in fact here I have the same kind of thing that we just saw right with the co-routines run blocking and I'm creating list is a function that takes an integer or size and some code of function that takes that an integer and returns a T and essentially what this means is that it's going to do this a hundred thousand times okay by the way did you know you can do that in cotton I don't like it but you can if you want so launched common-pool delay 1000 print and then jobs for each IT join join us like from the same concept of thread I don't think it's the best name nor does Roman that wrote this but he opens welcome to suggestions but it's basically going to wait and then print the result and I've got the threaded version here which is jobs 1 to 100,000 jobs for each create a thread sleep a thousand and print okay so let's run this with threads and we get unable to create native thread out of memory error okay and then we just get something printed not a hundred thousand now let's run this with the co-routines done okay so essentially it is not the equivalent of a thread as such right the idea of suspended computation i suspend at some point i do something and then i come back so this is and we'll see what this coming back and where i do this is part of this parameter that we'll see in a second now these are sequential so if I come here and see these are my suspended points so I have suspend first functions suspend second function right and what I'm doing here is saying this measure time milliseconds it's just a poor-man's or layman's version of performance testing right when does it start when does it end this block of code so here I have a first function call and then I have a second function and I'm going to print the result of adding those two and then I'll see how long it took to terminate to complete okay so this is return 13 it's going to delay for one second it's going to delay for one second and it's going to return 29 so you see that it returns 42 and you see that it took 2,000 milliseconds right because it is actually doing it in a sequential order right because these two functions are part of the same running block it's going to do it in a sequential order so how do I make this concurrent how do I make these co-routines be able to run concurrently so to speak there's multiple ways but the first thing that I can do is say a sink right and say run this in a synchronous way so don't wait for anything else now this goes back to I just said that we didn't introduce a sink oh wait no we don't introduce those as keywords as part of the language will you introduce those as functions as part of a library you can create your own co-routine you can create your own helpers and we'll see that there's a bunch of different helpers so this one if I run you see that it completes in one second essentially right now with co-routines then you could do sometimes these stuff for example you can cancel co-routines here as well so you know I can say job cancel and that basically what it's going to do is cancel all of those co-routines and this common pool thing that we've been passing all the time this is where the kind of like what thread this is acting on now if you're familiar with rx you know that you have the observer observe on or subscribe on and you can pass in the actual thread right which thread is this is this on a worker thread is this on a main thread so you can in fact subscribe on a on a main thread and then observe on a on a worker thread and then end up in a deadlock but it gives you that ability and and this is essentially the same thing right I can run on different threads so you have common pool which is the normal standard one that you use is just get a common pool from the thread and run on that unconfined means that I can run on anything and I can skip back and forth context is on the actual thread that it is so it allows you to also have control but the main key point to take away here is that really the co-routines is nothing more or nothing more I mean in terms of what it's added to the language is suspend nothing more that's the only new keyword under the covers yet there's a lot more because there's a state machine that's implementing all of this and making you know managing all of this but the rest of it is delegated to library other way you see that all of these are highlighted with like a little block right and that is because it's saying that this feature is experimental essentially and to make this clear it doesn't mean you shouldn't use this it means we think we've got it right but if people start to use and give feedback and say you screwed up we might need to change but if we change we'll make sure that we provide you with a migration path right so essentially means hit out enter and convert it to the new version right which is the same thing that we've been doing throughout the milestone releases if you're tired of watching these warnings you can just hit disable co-routine supporting car model or enable it and then that will add something to Gradle if it actually worked that would add something to great illegal so it adds the parameters Gradle that you can add it to maven you can add it to IntelliJ build system everything and then now it's enabled it's basically a complier comply compiler flag right which is saying that this is highlighting this as experimental or not and coming down here you can see that you know there's the core library of co-routines right and then you've got co-routines for jdk for niño if you're doing reactive rx there's also helpers to kind of combine the concept of code routines with rx right because remember that the programming model is somewhat different Rx is always talking about streams which are observable and then you're piping the results through different phases whereas with colu teens it's more about you can go back to that imperative model of programming but there are times with actually it is necessary or it would be helpful to combine both have this pipeline of calls and then get those results from multiple places and combine them in a single one so you can create you can use the RX utilities here for qualities to wrap this as like an imperative call okay there's co-routines for android which is targeted around android UI development that's for JavaFX your swing roman is the riders behind this and the geyser is amazing I mean he really is like he not only does all of the work he also writes the documentation and the samples so I don't know when he sleeps I mean he's got help as well but you know he's really good okay so yeah those are most of the things that I've shown you here are now available in 1.1 variants generics has been always available but high value s is the co-routines yeah those are the two main things that are now available in 1.1 but if you if you're using 1.0 most of the other stuff that i've shown you is is working okay any questions yes in terms of targeting JavaScript I believe it's in works yeah because the 1.1 release is essentially will so like JavaScript was experimental for many years is what Mark is experimental and it wasn't finished 1.1 we now made some adjustments we've cleaned something's up and we ported the standard library to JavaScript but Kali Linux is part of the you know it's it's its own library so there is no target yet for jobs ok well then thank you for coming my email if you wanted is Heidi at jetbrains calm or you can find me on twitter at h Hariri and yeah thank you very much [Applause] [Music]
Info
Channel: Devoxx
Views: 19,615
Rating: 4.9453926 out of 5
Keywords: DVUS17
Id: a7QpoMj2uIA
Channel Id: undefined
Length: 46min 24sec (2784 seconds)
Published: Thu Apr 20 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.