Diving into advanced Kotlin features by Simon Wirtz

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] alright let's get started my name is Simon and I want to talk about cuddling today so I myself I love cuddling I left to talk about the language and that's why this talk is happening today so but myself I'm Sophia Nia I live in Germany I work there and I've been into the ethic about the language for around 3 years now so I've started off as a Java developer I used it five years and to switch to Catalan three years ago and since then I've been teaching a language and also being kind of a pioneer for it so I'm also kind of part of the community and stuff like that I've started I've also started a blog so write about the language sometimes and you can find it in the bottom left corner this there's a link to it and so the agenda for today I'm this is all based on the latest version of Catalan which is one point 3.31 a released last month we're going to talk about a lot of topics and these are in fixed functions operator overloading high order functions which is a very important part of the language and also you can inline functions and then which are going to talk about lemonis with receiver which is a very unique feature of the language and also very quick topic is DSL and then we're going to talk a bit about delegated property so I had to drop generics because it's the ug topic very tricky topic and doesn't really fit into this talk today which is a shame but yeah so but what I edit is to experimental features which is in line classes and contracts ok so let's dive just right in I'm gonna sit down because I have a lot of coaches show today and the first thing I want to show you here is a very idiomatic way of defining a mapping : so what you see is a map of this is a there's a function of the central library actually and what you pass in is you pass in keys to values and there's a word to and this looks like a keyword which isn't which it isn't it's actually a function you you can make them obvious by adding the dot and the parentheses which the idea which the the IDE doesn't really like as you can see so it's suggesting to remove the dot in the parentheses so why you can do that is because this is an infix function and what actually happens behind the scenes so this two function really creates Paris so this map of takes Paris of something to something so key value can be anything in this case we have string string to string so this is what what in fixed functions look like so this is not a keyword it's just a function and we can create our own function this is actually an extension function cuddlin so we extend a list and we create a combined with function and we take another list and what we do is we combine both lists so this is a pretty naive implementation we just combined it by adding the left and the right side and return this combined version if we use this this looks like this can be can be used like this so we have one list we combine it with another list so we might want to do it like this we might want to remove the dalian the parentheses and then the ideas the idea is pretty intelligent and so it really suggests who at this in fixed modifier and it just adds it here to the function no this syntax is valid so a better approach of combining lists would be using the the plus operator so in Catalan you can't do that in Java but in cuddling you can use operators on pretty much every tab and we're going to look at this in the next topic so let's quickly recap in fixed function it's a pretty easy pretty easy feature actually so in fixed functions let us let us remove the V dot and the parenthesis from function codes and there are some restrictions though so in fixed functions must must be member functions or extension functions so we always need exactly one receiver of this function and we need exactly one parameter passed to that function so you can't do that with any function it only works if you have a receiver and and parameter one exactly and the most common common ones are two as we already saw and then there are bitwise operators like and or also shift operations and stuff like that we also have some on string like zip and matches and we have iterable stuff so there are a few and not too many so this features is not used that much and it should be used with care it can and can look a bit odd all right so let's move onto to the next topic which is operators what we have here is a pretty simple data class it reps to two integers it's also comparable but that's not important yet so please acknowledge it's just the data class it reps two integers what we can do in : is we can use we can create operator functions and this is a key word you annotate your function with it and there's a predefined set of functions you can use this operators plus is one of them in this case we want to be able to add numeric holders to two numeric holders and what we do what we do is we basically just at the a part and the B part together and create a new mutable object of a numeric code and if you provide this operator and just to show you I can't name it with any custom name the compiler won't allow that because it doesn't know what plus X means it only knows plus at this point and if you have that you can use this this plus operator here this is basically what I showed in the previous example with the list that's also enabled by by an operator function you can do that with - as well you can so here's the - example you can do you can have an increment which allows this syntax you can have decrement looks like this and this one is a bit more interesting so in Catalan you can have a get operator and this is basically what you know from array access in Java for examples we have these square brackets to access elements in the array in Kotlin you can do that with any collection type basically you can do that with lists and hash maps using the square bracket syntax but you can go one step further and extent basically all of your types and enable this syntax so what I did here some create the get operator and if so it takes an integer this can also be a string or needham whatever but in might make in this case so if zero is passed in we return the left part and if B is richer when is returned we return the B part otherwise we throw an exception so now you can go ahead and and grab the elements of your type by using the square brackets and yeah it works for 0 & 1 as you can see otherwise we throw an exception this one's not so interesting we have a contains operator if we if we define a contains operator on the type you can basically check whether the argument is part of your of your instance this makes sense for example for 4 sets you can you can check whether some element is contained in your set and in colony we have the in a keyword to check whether this is the case so whether so this is often used with sets for example 5 in set of integer to check whether 5 is part of this set and we can do that with any type so in in this case we check whether 5 is part of this numerical and we check whether a or B is equal to 5 and this one is also pretty interesting and we invoke operator makes basically every instance of your type in vocable and if you make a number of colors in vocable you can take any any instance of this America or like edit and invoke it as if it was a function basically and this is also how lenders work in the lamp in the language so if you have a lambda in the language its compared to function to an instance of a function type and it provides the invoke operator so that's why you can you can call the function with the parentheses okay so this is another another operator compared to it's redundant in this case because our chives already comparable but if it wasn't you could be compared to and this enables a number of operators so everything related to earth with medic comparisons and then we have arranged to this also comes for free if you have a comparable because there's an extension function arrange too and what you can do arrange is basically it defines lower limit and an upper for your types and you can check whether some element is part of this range and it uses comparisons similar to these it basically checks whether one type is bigger than the lower limit and but less than the upper limit and if we have a if we have a range we might want to be able to iterate this range which isn't possible by default whenever you have a type and you want to make it iterable in a for loop you need to provide an iterator and this is odd this also comes as an operator so you can make in this case we need to make the close range a you see the type here you need to provide an iterator for this and if you have that you can use it in a for loop so there's a lot of stuff you can do with operators and I didn't cover all of them but as we saw that there's a predefined set of operators we can use in color and you can't use everything as operator so you can't use your custom whatever you want you can't use your own function types as operators so there's a predefined set another way they all work by convention and so we we we saw the arithmetic stuff like plus and minus and and increment and decrement and we also saw that the in keyword is being enabled if you provide the contains operator also if you have a range to operator you can use the double plastic syntax then there's index access if you have a set and a get operator and the invoke operator is also very interesting for yourself we'll see that later and then others like compared to an iterator and finally destructuring which I didn't show so this is also enabled by by conventions and for example available for four data classes by default moving forward we wanna have a look at high order functions in the language so if I talk about higher order functions I mean functions that take other functions as arguments or return other functions but in this case we're just talking about the first part so about functions that take other functions as arguments mmm in this case we have a calculate function which takes a pretty simple integer first and then takes takes a function as it's the second argument so in Kotlin functions are first class citizens that you can pass them around as if you have a simple string or an int and we we don't use the so this is the the syntax for functions basically you define that this function takes the string and then returns the string but we can always provide type aliases too to make the code more readable so in this case I'm not using the V more of those function syntax but just use a readable name like int matter in this in this case we we just call the operation with the first parameter and return the value so you need to you need to be aware that if you use a lot of lenders in your code objects are being created because otherwise they couldn't be passed around it's we are still on the JVM in this case and we we need to wrap them into objects and pass them around so if you have a lot of them in an encoding you will have a lot of them you you you will ya have a lot of heap allocations and this will lead to runtime overhead as of course so but what the language provides is the inline keyword so you can make you find your higher-order functions in line what that means it's basically a fancy word for copy pasting what the compiler does is if you have an inline function the the code of the function will be copied to the places where you call that function so the the lambda is not actually being wrapped into an option and passed into the function but the function is is coming to the place where you're calling it so there's no need to create an intermediate object anymore and this decreases the amount of allocations on the heap certain situations will not allow you to use inlining if you have if you assign this operation to some intermediate variable like this and you do some something and later you you call that function with the intermediate variable so if you inline this function here you will see that the compiler doesn't like that and you can't use the operation like this and IntelliJ says that there's illegal usage of an inline parameter and the thing is that that it's it's basically the same code but you're assigning it to an intermediate variable and this doesn't work and this is because so you can always use inlining if you just call the function directly the function type parameters directly so in this case the operation if you just call it that's fine if you pass the operation around to another inline function that's also fine but it's not fine to - for example assign this to to an intermediate variable and the thing is if you assign something on the JVM you need to rev it into an into an object otherwise you can't assign it to a variable so if there's no object it can't be assigned to some intermediate variable and in this so that's why this is not working here the IDE actually suggests you at be no inline modify you can see that here and we can let the IDE do that so you can you can always let me know in lankey were a keyword to particular arguments which will mean that this function is not being in mind everything else will be inline in this case it doesn't make sense because you only have one function that could possibly be inlined and you're saying this one shouldn't be inline so this is a bit bit annoying in IntelliJ again says at this point that this doesn't make sense because the expected performance impact will be insignificant so yeah at this point and we can't do anything about it and it couldn't be in London there's another situation where you should think about not aligning your functions because if you have very long functions and you inline them you you have to be aware that this this code will be appearing in a lot of spaces and a lot of spots in your code where you call it so because it's inline it's it's being copied to various places so if you have long functions and you inline them the bytecode will be make be much bigger than expected high order functions can always be defined as extension functions as well so we can you can have an extension on int and you take another function that's totally fine and one example of often of a high order function in the sound library is of this before each function in this case i reimplemented it it's basically the same code just with another name to make it clear that this is not the standard library version what it does it takes an action and invokes this action on every element in in your collection or your iterable so an example of an iterable is obviously a list if you have a list you can you can call that each function and provide a lambda this lambda basically tells Veatch what to do with alle with all the elements what we do we check if if we find an even number and then we we return from yeah from what do we return at this case that's a question so I have a print line here and the question is will this ever be printed and I will answer that it won't be printed so the thing is that this return here doesn't return from from this function it returns from the out of function and this is called a non-local return in Kotlin so it's not really not returning from the local each battle returning from the non-local control flow and we can fix that with labels so what you can do you can you can label your return you can say that I want to return from from each instead of from the non-local function this is like a continuing a for loop so it's not breaking the entire reach it's just basically skipping the current element and going forward to to the next element you can also give your customer a label that's also fine and there's even one one other alternative which is using anonymous functions so this is not a lambda it's it's an anonymous function it's just like a function but without a name and in this case we have a funky with Y and if we return from that anonymous function the return will actually return from this function and not from the outer function there's a simple rule to keep in mind return always returns from the closest function declared with a fun keyword so in this case return returns from this one because the closest fun and looking back here this returns from this fun right so some some examples of the standard library so in in in Kotlin we don't have a synchronous keyword but we have a synchronous function which just takes the lock object and then you write your code which is then so this this function will take care of locking and unlocking your lock object this is a good example of an higher-order function which is also in line then we have use which is like in Java we have try with resources in coupling we have that high order function to to do something on a stream or some some auto closeable or closeable types and finally what you see a lot in coupling is stuff like that so this is collection operations on our list for example so you filter something you map and then you reduce and all of these are higher are functions so join to string isn't but map and filter are and they are also inline functions and go one step further and this one is pretty interesting as well so what we have here is an extension function and it's called do stuff and it's only available on list what we what we take you is another function and this function again takes the list as its argument and doesn't return anything what we do in the implementation is we call the provided function with our very own receiver which is this and this is this receiver in this case when we call this function so we have a list here and we we say we do stuff and we provide a lambda which is the argument we are expecting at this point what we can do so IntelliJ says here that it refers to the list which is the receiver this LST here so it really is referring to to the to the object we are calling the function on this is kind of redundant right so this basically is we're done and I'd like to remove that I'd like to be able to just refer to to the functions and members of my type which which I'm calling the function on and this can be this can happen and what you really what you just need to do is put this one in front of the function so if you do that this syntax looks a bit like extension functions again and you can think of it as extension functions it's it's actually called lambdas with receiver so this is a action type which has a receiver denoted by the part in front of the dot so the receiver of this part is the list but in the scope of this function you can actually use that function as if it was an extension function and this means that you can do this to ops so now we can use ops as a function of list since this is already referring to this and you know that you can you can just omit this in most situations we could also say just ops all of these are pretty much doing the same and it doesn't really matter which one you choose I'm just going to stick with this one and now this syntax becomes so it's compatible it compares like this you you can also see that the list itself is now exposed as this in the lambda you can see that here so now I can just say this dot size again and with this this part that's actually a functioning coupling which is called with so you have a width function you can put in anything like a list of string whatever and you this one is exposed as this in the lambda and you can do anything with it with it like it's it's called with so yeah well this was actually the right flight alright so I order functions of Idlewild aspect of the language obviously and you see them all around cut line and you can always consider using inline to basically reduce the random overhead it's important to be aware of this then there's one important thing is to remember the the difference between non local and local returns and finally we saw that Lemnos with receiver can help us to read very comprehensive code and readable code and this is actually a concept invented by Kotlin so this is I think the only feature that is not available in any other language and examples are with as we saw and also apply which is another they are called scope functions because you you bring some object into into another scope or you bring you basically bring your function to the scope of some object to be more process alright so the next example is it is SDS else so and when we talk about yourselves domain-specific languages what we mean is that we want to create a structure a language for setting up some domain object so one very prominent example is the Gradle T so we know that Gradle can be used with groovy but there's also cutland yourself and this is basically it sets up two sets up a build and since cut learner's types if you do it in a type safe way you use that DSL type safely yes its type safe to use it and and what we what we need to what I need to show this what I need to show this this feature of DSL is I need a domain object and I thought it might it might make sense to use a conference the main object in the conference it has a name and the location and it has a schedule which is in this case just just a list of talks and so what it can't what can do is you can add talks and you can get the the list of talks and then a talk can can be a conference soccer keynote talk and talk as obviously a topic a speaker and a time so if we were to set up this domain object we would we could do something like this this any any Java developer would probably do it like this you might want to use a builder pattern for this to make it more clear what's happening there but what you're doing is you're creating a conference then you're creating two topics and you're adding these topics to the conference right so in Kotlin what you would what you could do is use the apply function if you would do conference dot apply you could you could just add talk without again referring to you two to the conference object like this this would look nice about where we want to go one step further what we want to have is a DSL and the dear silent curtain looks like this so I think every one of you has probably seen something like this already it's a pretty coming in groovy as well for example and what we have here we have a conference block and we set a name and a location and then we open another block of talks and what we do here we have different different different ways of defining our adding talks to our conference this is just I just added different examples to show what's possible so what you could do is have have simple factory functions like conference talk and you you would receive all the are the arguments you need to set up the actual talk object the same goes for for keynote talks but and then this one is a bit more interesting so we have here is it's basically a chain of infix calls so we have conference talk we say it happens at some some time and it's given by speak and it's titled whatever and finally we have we have an example of a often overloaded operator in this case it's it's a plus operator and we have best be saying we plus the talk which will at the talk to to the list of talks in that conference and what we also see a what we also see here is we don't have to provide a whole block of conferences we can just add a single conference as well and I also want to show you how this years I look looks like so the entry point is obviously this function this is again an inline function and it takes another function and this function is is a lambda with receiver so the receiver is the conference's which is the most important part of this year so obviously I will show that in a minute and what we provide here is a config so we call the conference with with a conflict which is this block this is basically you can also see here again that this refers to the conference to yourself and that's where we can just call all the functions of this DSL without any additional qualifiers like like it this is not not necessary what we do then is we we create the receiver of our of our config and then we apply the config and so applies as part of the standard library again and what we do then so once we use we we applied the the config on our receiver we we have a fully initialized conference DSL object and that conference DSL also exposes the properties we need to set up our conference so we retrieve the the name the location also the the talk list and set up our conference so there's a lot of code which you wouldn't like to write but if it was provided as an IP I that would be not an issue so there's a lot of code you need to write to provide the DSL obviously but as a user it's nicer to use it in certain situations so let's take a look at the conference itself the conference dsl itself so the conference dsl has as a private backing property talk list which is a list of talks and it also exposes to talk list so you can retrieve your chocolates it also has a name and the location both of these are var so in coupling you have var and Val's of L can't be reassigned while scan and and this is already everything you basically need to enable this syntax you you aim the scope of conferences as so that means you can just access name a location which are properties of that type and you can you can reassign it to something else that's easy which is not which is a bit more sophisticated is this part that talks this is a property and it's referring to another inner DSL so we have an inner class at or configure so that took tongue talk config these are also refers to the talk list of the outer conference ESL and it hasn't invoked operator we saw that earlier and this invoke operate again takes a lambda with receiver of its very own type talk on 50 as well and it if if invoked like this it will apply the convict 2 to itself so the invoke operator enables us to use this talks variable which is of type talk config DSL and provider lambda so because the talks is in vocable we can invoke it with the lambda we can provide on an argument to the talks so this is the config for the talks variable which will be applied to the DSL object since this is a normal reference to an object we can just call its functions like here so actually the the invoke is just the workaround to enable both syntaxes otherwise you could always do this syntax but we obviously want to have this index as well we want to provide different talks and that's why we added the invoke function here so let's see how the functions in the talk configures I look like we have a conference talk in a keno talk they are as I said pretty simple they just add and so they take all the arguments provided and create a talk and add it to the private list that's all these are more interesting so we we have again two properties of that talk convict user and when is conference second one's keynote Chuck and they basically give you an empty talk with the type right so you can use that empty talk which has a single in fix function it has an odd function and it takes the time and it will give you time talk this time talk again comes with another in fixed function called by which takes the speaker which will give you in time to North attack this time the north attack will finally take the topic with another in fixed function and add it to to talk list that's something you don't want to implement but it's it can be nice to use it because it's it's a pretty readable thing in the end so it reads like a sentence basically so you have a conference talk at some time by a speaker and it's titled the cloud last but not least we we have a we have a we have an operator and if you define extension functions as member functions over type they are only available inside that type so they don't pollute the entire workspace of the entire namespace of your work your workspace are your project and they can only be used in this particular DSL and what it does is it's just at the the talk itself to to the chocolates that's pretty simple and just to make it clear I can't go ahead and use conference talk here it doesn't know this and it's only available in this scope as well as this plus operator can only be used in this talks here so you you get some kind of structure by applying these cells all right so do cells they are pretty much a design pattern for expressive APs and they create a structure and language for your domain objects to set it up and they also enable a lot of code usability so you can obviously use your own coupling code inside the DSL you can have loops inside inside the DSL to set up when come an example is an HTML DSL to create type safe HTML code and it's it's a combination of many language features obviously so we saw Alumnus with receiver we saw in fix functions which which lets you provide English like sentences or constructs there's actually a test library for coupling which uses this and you can also use member extension functions the invoke operators pretty common and a lot of other a lot of other features as well of course okay let's move on to delegates so when we talk about delegates we we mean that we want to delegate the the logic for some for accessing some property of your type to to another helper class and what we see here is one example of a lazy that like delegate whenever you see the by keyword that that means that we're working with delegation and coupling so let's just see what we have here we have a simple class and we have an init block so that that means if the object is being created it will print out something that's all and then we have the first example of a delegation property of a delegated property in this case we we have an integer and we say by lazy lazy it's not a keyword at cutland it's a function which gives you a delegate and so you always have the syntax by which is the keyword and then you which is followed by the actual delegate in this case lazy and this one takes the lambda and in this code you you basically say what happens if this property is being accessed for the first time and it's actually being being executed only once when it's accessed the first time that's what lazy means and you can even use lazy l in local so in functions as local variables for example if you have some current you want to define all your variables you might need at some later point at the top of your function you can do that and if they are if they mean a so if they imply a heavy computation you might not want to actually call them because you you might not know if you really need them in the end so you make them lazy and only if they are really accessed at some point later in the code they will be computed computer to you another example of a delegating cut line is be observable so observable is it's pretty simple you just provide a callback and this car back will be invoked every time you your property is being reassigned so if if this property is is being changed from the outset this callback will be invoked and you can you can do simple and yeah simple stuff like just printing out what happened so the value change but you can also use it to notify some other some other part of your system like the UI that you can tell it that your property has changed please update it in the UI which is a common common use case for this and going one step further we have v2 abaut and this this is also an observable it has the capability of saying no I don't want to assign this value to to to my property I am so we also provide a callback here but we we return actually a boolean so if we return false from that boolean we are saying that we don't want to have this values assigned to to this property in this case we allow all values lower than lower than 11 so so if you have a value that is greater than 10 we say no we don't want that well so we return false and and else we just return true and last but not least you can obviously also have your own delegates so you can implement your own delegate delegates delegate classes in this case we have a modifying delegate it takes an initial value so we are basically initializing this integer with 100 but we're also applying a modification function so to speak so this one takes the lamda which does something with the value that that is being passed that's being assigned to to this integer in the so in the initialization what will happen is that I used 100 and will it will be multiplied with with 10 so the actual value of this property will initially be 1000 this doesn't make sense but it's just an example of how delegation works and this is actually the implementation of the delegation class so the modifying delegate takes an initial value and it takes a function of the modifier what it what it has here it has a private property current which is only the initial value applied all the modify applied on the initial value so this is the initial value actually and whenever you you call get when the current value will be returned on the other end if you set a new value which is this one and the modifiers being applied to that new value and the current is updated so these functions they're hard to remember the this this look a bit weird and what you can do is you don't have to but you can't implement interfaces provided by by the constant library you have the choice between readwrite properties and read-only properties so in this case we are only dealing with readwrite properties and if you implement this you can let the IDE generate this code for you and just provide the implementation so here's some code executing this so executed using this delegation stuff so what we do here is we access lazy one twice and what we're expecting is that the initialization of this lazy one so this is basically the name the name of the property which we used with the lazy delegate at this point and you only see that lazy in it once because I and you can also see that it's not invoked directly but only after we created the object and called the lazy one property here and it's not not happy a second time if we assign observe property we see that the value has changed and we are setting verified property to six which is fine no veto setting in 2/6 not fine veto and if we then print the current value of every property it's still six so 11 has not been applied finally the the custom delegate we set it to 2 and the value then is 20 because we multiplied with 10 and the modifying delegate right so delegated properties let us reuse property accessor logic and this is always denoted by the by keyword we we also have class I'm not sure if it's called last delegation but you can actually also delegate to implement a so if you implement an interface in cutland you can delegate that to a class way you can for example have your own map and delegate the map implementation to tune internal map or to private property which you have in your class and but this is a bit different but still also uses the by keyword and the compiler will generate all the XS our logic for you so if you have the by qubit in your code it will actually in the bytecode have another property referring to that delegate and whenever the the actual property is being used it will delegate to the property using the set value and the gate value functions right so the this feature is sometimes used in will sometimes be used in your code but it's also very often used in framework and lab record so this one one example which is the exposed library which is it's an SQL generational every written by JetBrains and they use it a lot to basically abstract the the access to table fields in SQL right so the the next topic is in line classes and as I mentioned earlier this is an experimental feature so um Kotlin introduced this kind of experimental features to say that this might change in future releases so what that I'm gonna show next is is the current state of the language but it might change in future releases so in length classes if we have a simple API method authenticate it takes two things in this case it takes the user in the password and you can use it basically in in two ways you can you can use it in the correct way applying the username of the password you can confuse the the order of the properties which is not very very it might not happen in this case but if you have a lot of boolean so strings this might happen the you're gonna confuse the the order of the properties and this is happening because they are all of the same type which is string here so this doesn't give you next a compile time error whether it will fail at runtime what we what we can always do is rep symbol tabs like strings and integers in another wrapper type and you can use classes for this mmm but in Kotlin you can you can also use inline classes and the cool thing about inline classes is that if you have an inline class this will not lead to actual object allocations so if you have a string and you wrap it in inline class you won't have that name object in the Bayeux code this is not entirely true it might happen there's something going on like boxing which you know from from the integer type in Java but the compiler will try not to use this class in the bytecode so it will optimize it by just using the rep type or the underlying type as how it's called so what we can do is we can wrap the name and the password and we can think of this as subtyping the string and we're using this these types in the authenticate method then and what we have then we we we can't confuse the order anymore because the compiler will tell us that this is not valid we can't just change the password in the name so it gives us more type safety another example that might make sense here is the is something like this so we have a function that takes a number which is a string and it passes this into a big decimal by setting a scale so it's basically you're not taking the entire string but part of it and setting the scale and also rounding with the half-up technique here so we we have that and it might happen that the requirements change and we we might want to preserve the original value which is the string this so if you have something you pass it and you also want to preserve the original it might make sense to just create a class and provide that functionality that makes sense but if you use it if you use these types a lot these will mean a lot of heap allocations and again it might make sense to consider in line classes here so this in line class reps the original string and in line classes can have functionality in their value so they can also have properties which must be calculated property so whenever this passed values is accessed the get method will be called and it will actually do the calculation so this is not cacheable in this case it has to happen every time this is a yeah we can say it's a downside so the trade of that at it needs more calculation at runtime but the cool thing is that you can now use the palpable number with these two properties and as an IP I user this looks like they're just simple properties and and it's important to again note that at compile time this possible number won't exist and this this past year is being enabled via static functions so there will be something like a past function it will take the the original string and then return the big decimal pretty much like this one but we are still preserving the original yeah so again it's an experimental feature it might change but it lets us wrap types without runtime overhead and it can can be used for simple typescript simple types and as I said normal classes of course employ heap allocation so that's where we might want to use inline classes instead and it's important that if you have a name class which wraps since with wraps the string and we have a string on the other hand you can't just assign them to each other they are not assignment compatible on the other end type Elias which I showed earlier is Simon compatible and in our case it's only work if you if you have a single property defined in the primary primary constructor so this is the underlying type of this inline class but we can't have functions in the class and we can also have member properties well--that's but not least I want to talk about contracts in : so consider this code we we're having a function here which takes a nullable version of a list of strings so as you know already probably the question mark denotes that this is not able so that it can it might happen that this is now and what we do here we check that it's not null and it's not empty and in the next line what we want to do we want to print the size when the compiler doesn't like that it's it's selling us basically that it it can't be sure that data really is not null at this point but we we checked it here right so we're expecting because the coding compile is pretty smart and it can normally do these kinds of things but in this case it can't and the reason is that this is a this is a function here so it's not empty as a function it the compiler doesn't know what the function actually does so does it really check that it that the type is not now if we have a look at the implementation it does check it so it checks that so it returns it checks whether this is now all this is empty and we're checking that this is not the case so we are checking not is now empty so what we can do in Catalan since version 11.3 we can add a contract here which is also DSL and this looks like this we we still have to opt in to - you know I I'm confused okay here we go so we can't we have to add an annotation and say that we were using the experimental feature of contracts this is a bit noisy and it it's not nice but it's the current state and what we have here we say that the contract if it returns false this implies this is not now and we're basically telling the compiler a bit about the function we're actually having here and now this code is fine and it actually says that a smart cast happen to to the non inaudible version of a list that's not another example where contracts makes sense if you have a value and you you assign this value later this is fine so values can be assigned once they they must be assigned exactly once and if you if you have a function or you you delegate the the the initialization of that property to a function like here to let the component doesn't like that because it might do so the let might call this this function you provide multiple times and this was me this would mean that the property of the the variable would be assigned multiple times so it doesn't allow that and again we can we can use contracts to to solve that and what we do then is we say that if if this function is called it's being invoked exactly once so we we tell the compiler that this function will only call block once that means that this assignment will only happen once so that's what we can do with contracts also experimental feature but they they let us help the compiler understand our code so smart casts are always based on performed checks like if something is not now and then those markers will happen but this is problematic if the checks happen in a in a separate function and yeah the contracts let us let us describe how how functions behave and one thing to remember is that these contracts are not checked by the compiler so whatever you say in the contract the compiler will believe you so it's your responsibility to make sense of this feature yes sir a little summary and this is really simple so as as we saw Karlin has a lot of features and they they might look magical at first but it's I think it's very important to know how they work internally so I always say you should read the documentation which are pretty good and the best book out there is Kotlin actions if you haven't read it please please grab a copy and and read it it's it's it's based on Java developers and it tells you a lot about the internals and how the how the language is implemented so the the authors actually they they involved in the language they work for jetbrains and they know what they're what they are talking about so that's it thank you very much you can find the code there if you like on github and yeah thanks we actually have two one-minute so one question would probably work otherwise I'm around so you can just come to me afterwards [Music]
Info
Channel: Devoxx
Views: 14,432
Rating: 4.9057593 out of 5
Keywords: DevoxxUK, DevoxxUK2019
Id: zmqhe7fDEHI
Channel Id: undefined
Length: 49min 37sec (2977 seconds)
Published: Thu May 16 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.