 Thank you. So hi, thank you for coming. I was very lucky that for most of my professional life I was able to work with Qt in one way or another. We just changed about one and a half years ago when I moved on to a completely new job, new project and we use pure C++ and I was quite surprised that I found my way around the new codebase fairly quickly. I could, you know, start using the internal APIs, the libraries we have and it was, it felt natural to me and I didn't think too much about it until a couple months later when I was doing some KDE hacking and for like the one thousandth time I had to go to the Q documentation to check on the ownership of Q network reply and that's when I realized that the reason why I was able to find my way around the new codebase at my new work was because the API was very expressive. It tells the intent that the developer of the API has so that for me as a newcomer it is very easy to understand oh so I'm supposed to take over the ownership or oh now I'm supposed to pass the ownership and so on. So this talk is showing two really just two examples because otherwise I could, we would be here all day but I've sure picked two examples from modern C++ that I really really really like and I want to present them to you. So you can see that these APIs are APIs are similar but they don't really express the intention right the first one actually transfers ownership you are supposed to delete the Q network reply yourself the other one does not. So this would be an easy fix right this already tells the intention that well the Q network access manager actually gives you the network reply and you are supposed to delete it while the other one well you don't really know what to do with it because it's just a raw pointer so you better not touch it. The thing is Qt is often heralded that it has its world designed very stable consistent API and rightly so the problem is that lots of the parents are based on you know 20 years ago and even though we say that now we use C++ 11 or 14 if you really look around not just the Qt code but also Kd code base what you find is we don't really use C++ 11 we use still use C++ 03 and we just sure picked auto and lambda send that's basically it we don't use much else from whatever the language has right so when I speak about C++ and modern C++ there are two parts of it there's the core language the language itself and the syntax that it has right so this needs to be supported by compilers so for C++ 11 those were lambdas for C++ 14 this was function template arguments deduction the other part is the standard library right that's all the all the template classes and algorithms that are part that come with your compiler and sometimes those do require the new API but sometimes they don't sorry the new language features but very often the library features that come with C++ 17 for instance that could very very well work with C++ 14 as well so the two examples I'm going to show they are from C++ 17 and since we do not use C++ 17 that much in Kd you can very easily find lots and lots of well not that many but you can find quite a few like a single header implementation on github that are compatible with C++ 17 but they can be used with C++ 11 or 14 very easily so here are the two cases what if so what if a function may or may not return a value so how do you express that you have a function and the function may not find something or it may fail you can imagine some settings class right that reads values and it may not find the option in the config file so how do you express that well we could throw an exception but we don't like exceptions that much so we could return a pointer right so if we find that option in the config file it would return a pointer to rectangle if it doesn't find the option it would return an all pointer this is annoying though first this is a value class because rectangle that's just a value so why would you return a pointer to a value class and how would you return but and you wouldn't do this with integers right you would not return a pointer to integer just to be able to represent a lack of the value so what you do well you could pick a random value and say this is a special value and this special value means there is no value so sometimes we pick zero sometimes we pick minus one sometimes minus two sometimes minus max int or minus max in plus one or something like that but this is problematic because not always you can do it sometimes you have a function that can fail but it also if doesn't fail it has to use it can use all the values from the range of the type this is a perfect example this is a horrendous C style 1970s API what the hell is this doing in my 2019 code base right I don't like this function at all I hate it first it doesn't actually force you to error check because because there's the null pointer as the default argument to the error checking right so basically if you are just lazy or a new programmer and you do not know about this you might be tempted to somewhat forget it so what I would do is probably well I think I'm missing some slides but normally you would probably get rid of the null pointer at least to actually force the developer to say well I know what I'm doing I'm passing in a null pointer explicitly the way we do this in Qt very often is that we define a null state of the type right so we have Q string is null and Q rekt is null and Q size is null this is also a bit problematic though because you have a function that actually returns a value of type Q string and now it doesn't tell you the intention that well it could it is a Q string but it is in null state so it actually is not a Q string because we haven't found it so this puts the burden on you as a user of the API to realize so do I have to do the error checking here or is this okay can this fail do I have to check if the Q string is now or will this always succeed you can't really tell right and we are most trusted developers we don't want to error check everything and there are of course classes or types that cannot have a null state right so I cannot have a null state of color because well what but I feel for all the three colors all of the three components because well if I put zeros in there it's not a null color it's it's a black color right and like is a very cool color so I need something else and the thing that C plus plus offers is STD optional STD optional is a template class that either holds a null value or it holds a value of type T so this way I can so this is so this explicitly basically says that well there is either nothing or there is something in me then you have to check so we could have the same API as we had before to read some settings and we could have a function that reads a string and read on some STD optional Q string right because this explicitly says this may fail and it may return nothing and you have to do the error checking and then you can have the alternative overload which like gets strength or default which takes the second argument second argument and then if it doesn't find the option in the config file it will return the value of the default the default value so the function will never fail so it returns only a Q string and you know okay so I don't have to do error checking here because I will always get a valid value that I continue to use I forgot to apologize beforehand for the amount of C++ code in these slides it will get worse so this is an example of how you would use the API right the STD optional has a very nice getter called value or value underscore or so it either returns the value stored in the optional or if the optional is null it returns the value give it so this actually means you would not need this second overload even you can also check if the name has value and then you can try to read the value or the reference it and you will get the value this really forces you to do the error checking because you got something that is not a Q string it is an optional Q string so you know you have to do error checking also because if you try to access the value and it contains a null value then it will throw an exception and abort your program so you do want to check the value so this was one example other example is what if a function wants to report an error so you have a function that I don't know tries to read a file access network whatever and it fails and you just don't want to fail silently you want to tell the user that something went wrong or you need to pass some details about what went wrong to the calling code so how do you do this well you could throw an exception but we still don't like exceptions so let's try something else inspired by Q string to end we could use a return argument I've already mentioned before return arguments are evil and you should not use them especially not with a default value because then you are basically letting the developers be lazy and because developers are lazy you should do this so you have you force them to explicitly say I know what I'm doing or I am explicitly have the developer to admit that he's lazy and pass in an out pointer ideally you would you won't even give them a choice and you actually force them to pass in something it's up to them if they then check what's in the error afterwards but that's a different discussion so what if we do not want to use return argument well then we have only one option and that's we need we need to return somehow multiple values from the function so we could just return a struct which either optionally contains an error or it contains the JSON document for instance if it's a JSON parser the problem here is that it can sort of be an it has a couple states which are not really sensible so what if the function fills in both right then that's not defined state or what it doesn't fill any of those that's also weird state there was no error but there is no document either so what the hell happened so it would so we need something even better right we want the function to be able to return two types but always only one of them right there is this thing that for some reason everybody hates that's a union and C++ 17 introduce a much smarter version of union called STD variant do not confuse STD variant with Q variant those are different things while Q variant can hold literally anything STD variant can only hold one of the values of the type that is specified in the template right if you would something if you would want something like Q variant there's STD any which is weird so this is what the function would like so the function returns an STD variant of JSON document and Q string so it returns a value which is either a JSON document or a Q string cannot be none cannot be both it's always one or the other that of course can be more of those variant can have any number of types but in this case my two makes sense but this is still not really expressive right this doesn't tell me what the Q string actually means is it I don't know is it a hello world is it how long it took it could be anything so I would do something like this define a type def to Q string call it error message and then I can see that the function either returns a JSON document or an error message right this is single easy one line of code it has no compilation overhead no runtime overhead it just makes your API more expressive more easier to use for other developers to showcase another reason oh this is crazy but this is how you would use it so STD variant has this get if thingy so you can ask if it contains another message then return a pointer to it the other option the other way you can do it is you can check if it holds alternative then gives you true or false and you think STD get you get the type it holds this is very similar to the API you know one of the things I like about the variant in C++ 17 is that it also introduce STD visit which allows you to write basically using the visit pattern so at the end and I'm a bit abusing it but it still work very nicely because it allows you to put all the things into a single block so you you have your success and error handling in one block of code right so at the end I will start from the end at the end is the the variant that you want to check and then you put in a lambda that is called when the variant contains the JSON document and then you put another lambda that is called if the variant contains the error message this doesn't work on its own you need to do this overload template magic if you want to look this is not part of the standard but just copy paste it from CPP reference like I do every time it's a two-line template and so this makes your life much easier as well so these were two examples of how you can make your API way more expressive than just returning a pointer or a queue string without telling the user any more information the conclusion would be use smart pointers obviously we should have been doing it for decades not in the past three years use optional use variant use all the nice things that modern C++ has if you can switch to actual modern C++ so that means if you can leave C++ 11 behind which is 80 years old by now and switch to something that is not so old maybe just two years old then switch to C++ 17 it has some very nice features that will made not necessarily can improve the expressiveness of your API so whatever but it can make your code in general more readable and well that was fast so thank you and any questions I guess that's one of the features of C++ is you don't pay for you don't what you don't use and so we have lots of time for other questions on more techniques so we obviously are not using these things in frameworks how would you go on doing this because like that probably means breaking the API like like the AVI event because you need to change your sure I don't have return times are part of the area but there's things to be changed right so do you think it makes sense to do it now wait for frameworks six if that ever happens or yeah that's a great point I think now is a really good time to go fix this in Qt for Qt 6 and start looking into doing this for frameworks and probably you know it's not like now go and change everything to optional you need to think about you know where this makes sense and probably some guidelines some thinking how and when this should actually be used my initial initially I was really excited about this thing so I tried started putting it everywhere and then realize this is not the right way to go so but yeah start putting in somewhere it breaks API but we have to at some point to move on otherwise we'll be stuck with the C++ over three forever so just one comment regarding variant for well okay so what do you think I'm going to rephrase it what do you think about libraries like boost outcome and boost expected as a replacement for the exact use case of variant that you had right as far as I know there was STD expected proposed for 17 but they not get in right so sure yeah use boost if you want to use boost boost awesome other questions at the keynote about Qt 6 it was mentioned that the containers were wrapped in standard containers and I thought about all the cute pointers we have like Q pointer and Q shared pointer and all of these and when they're C++ equivalence of modern C++ so what's your opinion on these can they be also like share concepts or be replaced or not everything probably I don't know enough about the differences if we can make Q shared pointer just a type def or wrap around STD shared pointer and stuff I don't know one thing I know is that we either should have a Q unique pointer or get rid of Q scope pointer and force everyone using STD unique pointer because right now we have Q scope pointer and unique pointer STD unique pointer which are very similar but not really right because they are not the Q scope pointer is not movable and as far as I know they tried to make it movable then realized this is stupid and reverted it so so which compilers can actually build code like this sure JCC can clank can what about MSBC and yeah what I'm aiming at is more like this is this is a new code and code like this tends to uncover compiler bugs and the next question is did your code ever find the compiler bug so the supported compilers is recent enough GCC and there's been GCC parties for a couple years now so does clank even on BSD on mega as well on Windows the latest original MSBC has C++ 17 support I don't know what state their standard libraries in but because I don't care about Windows but well you can compile it on all platforms if you have a recent enough compiler that's I think the except for haiku and this weird stuff I have no idea they probably still compile by hand the second question no I don't think I found a compiler error I found a linker error in link time optimization that's fun to debug other questions if not thank you Dan for your talk