 And we have a Luffy and Hamelo, so we'll be giving our keynote for the day and Luffy and no audio. Thank you very much, Kalian. Thank you very much to the Picon India organizers for the honor of inviting me to present a keynote. It's really awesome. I've seen the, the, the other speakers and it's an honor to be here. So I work for ThoughtWorks. ThoughtWorks is always hiring. We have several offices in India. So if you want to work for a cool company, try and look at the ThoughtWorks.com website for opportunities to join us. So I wrote this talk, so the talk is called Type Hints, Protocols in Good Sense, and I wrote it because I observed something that Raymond Hettinger also confirmed in this tweet, which is he said that he thought that a lot of the talks given about type hints were given by people whose job were to promote type hints in their organization. And that's fine, you know, but the problem is that then people tend to avoid talking about the problems and the downsides, right? Nothing is perfect. So these type hints are, you know, to summarize my position on this, this is sort of my spoiler slide. If you go away now, this is the main message. Python's type hints are ready for use, but they are not perfect. You should understand the caveats and the workarounds and realize that sometimes avoiding using type hints is the best solution. Okay, so you may know me as the author of Fluid Python. My book has been published in nine languages. The edition in front is the edition for the Indian subcontinent. I was very happy when that came out. And I am now finishing the review of the second edition. That's going to be released this year or early next year. And it will be it's I am updating it to Python to cover Python 310. Okay. And so, who am I to talk about type hints. I've been using Python professionally since 98. But at first, I did not like type hints. I thought they were a bad fit for the Python language. And there was a new feature added about three years after type hints appeared in Python. The typing protocol was introduced and I'm going to explain to you why I think typing protocol is very important for using type hints in Python. And when that came out, then I said, okay, now I think we can use type hints or at least I could. So I am now a happy user, but I use it with moderation. Other contributions that I made was that I realized I reorganized the documentation of Python's typing module in version 3.9 of Python. In collaboration with Guido, it was a pleasure to work with him on this. I've been contributing bug fixes to TypeShad. TypeShad is a repository that has type annotations for the Python standard library. Because the Python standard library doesn't have type annotations yet. There's this project in the Python organization on GitHub called TypeShad that brings together type hints for the standard library and other important projects. And all the tools that do type checking use those type hints. And I did a lot of research for type hints to write about them. I did more than 100 pages about type hints in my book and dozens of examples in the second edition. Okay, so this talk is divided in four parts. First, I'm going to talk about the current state of static typing. Then I'm going to talk about the four modes of typing in programming languages and Python in particular. Then I'm going to talk about the central role of typing protocol. And finally I'm going to talk about typing limits and how to address them. Okay, so the state of static typing in Python. For maybe some of you in the audience have not seen type hints yet. That's how they look like. These are five declarations. And I'm using in those declarations two features that are new in Python 3.10. One is the type alias hint that is to you did not need to use it. You don't need to use it actually, not even in Python 3.10, but it's good to use it because otherwise it's just an assignment of symbol equals string. Which could be misinterpreted by type checkers and by users. So this type hint type alias is a new thing in Python 3.10. And it's useful to make it explicit that this assignment is actually giving a new name to this type. So this assignment is saying that in this module, sometimes I'm going to say that things are symbol, something is a symbol, but that actually means that is a string. But I'm calling it a symbol because it's a string that I'm using in a particular way in the program. So it's really just an alias. Python example is more interesting. This the pipe operator is now available in Python 3.10 to use instead of the union special type declaration. So what I'm saying here is that number is a is the union of the int and float types, which means that a variable. Annotated as number can be either an int or a float. Okay. So atom is another alias in this case with pre a union of three types. Then we have a union another union and finally here this is an example of a generic type annotation mutable mapping is a generic. I mean, it's an ABC and abstract based class from the collections module. And here I am declaring that an environment in this program has to be a mutable mapping where the key, the keys are symbols, and the values are objects. Okay. So this is a little bit of an example of a program that uses those annotations. So, here we see that this parse function takes source source code, which is a string. And it will return an expression. Right. So this guys takes a string and returns a list of strings, and so on, right. So this is how you declare types and use types. Sometimes you don't need to declare them before, like the beauties, or the generics that are built in. So this is the how they look like the type hints. Now, I think probably most of you know about static typing and typing, right. And this has to do with when the types are checked. So static typing means that the type checking is static, meaning that it's the type checking is done. Looking at the source code, the tool that does the type checking, maybe it's the Java compiler, or a Python type checker or an ID, whatever tool you use to do static type checking will just look at the code at the source code. It will not run any, any part of the code. Right. On the other hand, with dynamic typing in languages like Python, JavaScript, Ruby, small talk, etc. PHP. The type checking is done at runtime. Right. So if you try and divide the number by a string in Python, the interpreter at runtime will raise a type error saying that you can't, you know, you can't divide the number by a string. But now there's a new thing called gradual typing. So instead of a binary choice between static typing and dynamic typing. You have languages that now support gradual typing. That means that you can explicitly write the type annotations in parts of the program, but not other parts. Type hints are optional in this scenario. And also the characteristics of a gradual type system of, you know, which is what Python now has is that, first of all, it's optional at all levels. You can still write complete Python programs without any type hints. But you can have a program that is entirely annotated with type hints, but then in a specific place, you can turn off checking of a line. You know, maybe because usually when I do this is because there is a bug in the type checker or the type annotations from typesheds. Right. You are able to turn off checking in specific lines. Right. Sometimes also the thing is you're importing a library that doesn't have type hints. Then you put a comment, a special comment in that line, telling the type checker to ignore not try type checking the library because it doesn't have type hints. And also you don't want it to keep warning you that the library doesn't have type hints because you can't fix that. The library belongs to a third party. Okay. The second thing is there is a default type and the default type is the any type. And any type is kind of weird because it's more general than objects. But at the same time, the type checker understands that any is complied with all interfaces, provides all possible methods. So it is at the same time something that is at the top and at the bottom of the type hierarchy, the any type. Right. There are some statically typed languages that have some something similar, like for instance, in C sharp, there's a dynamic type in go, you can declare an empty interface type, which is the same idea. The third thing is type hints don't catch errors at runtime. So if we go back to these slides here. In the first example, line 93, I am saying that parse takes a source argument that has to be a string, but this check only happens. You know, before the program is running when the program is running I can pass a float. And there will be no error raised because of the call. The source, which is a float in my example will be passed to tokenize tokenize only accept a string but also the bug will not be flagged here. What will happen in this case is that because s is a float, it doesn't have a replace method then you have a runtime type here of the same kind that you would have if there were no type hints, right. So this is very important to understand that type hints have no effect at runtime. Unless you your code does something explicitly with them, which I'm going to talk about in a minute. Finally, type hints don't include and don't increase the performance. Currently the Python interpreter and other Python interpreters like pi pi. They don't use the type hints to generate optimized by codes, they could maybe in the future but they don't at this time. Okay. And and grad gradual typing is something that is now present in other languages. It's I think the most important the most famous language that uses grad gradual typing is TypeScript. But also the dark language that is using the flutter SDK for mobile development by Google. That language is also gradually typed and hack, which is a PHP dialect used internally at Facebook is also gradually typed. It's also important to note that the authors of the Python enhancement proposal for it for the document that specified type hints in Python the authors made it clear. They wrote that Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention. Okay. But in reality, in certain environments in certain professional contexts type hints are becoming mandatory by convention. Okay. More and more teams are adopting by teams type hints and expecting people to use them. And my talk is actually my goal in this talk is actually to encourage teams to use type hints, but to use them. You know, with moderation, meaning, don't force everybody to use them all the time and I'm going to explain why. Okay. The best feature of gradual typing is really the fact that type hints are always optional. Okay. So how are type hints used. Probably the most visible benefits of type hints for everybody is that the ID is such as by charm and VS code and wing ID. They become smarter. Because because you're using libraries that have type hints, or they have that there are type hints for them in typesheds. So complete works better when the when the idea understands the types. You have instant warnings, you know, those weekly underlines. There's better refactoring assistance. So while also, two tips, you know, saying what the arguments are. And while writing codes, even if you don't use type hints in your code, you can benefit from libraries that use type hints. Type hints are also used for for LinkedIn. You know the same way we use, you know, flake eight to check several aspects of our programs. You can use a standalone type checkers like those that I mentioned here. You can verify the type declarations and to verify that your code is compliant with the type declarations. The same standalone type checkers that you use for LinkedIn in your machine, you can install in the build servers as part of this continuous integration pipeline. Right. So when somebody uses a code, the code can be checked. Not only, you know, the CI pipeline can run unit test but also can run type checks. That's useful. Those are the main use by far, okay, of type hints. To a lesser extent, there are some type hints that are read by Python at import time when you load the module, because there are some new features of Python that I call the data class builders like the data class decorator and typing dot name it double, which are now available and you can use type hints to declare the fields of the classes. And it's also possible to use type hints at runtime to do explicit type checking. A very important trend is that you can now use external libraries like by Dante that, in fact, you know, you have you had a keynote by the creator of fast API, right. I forgot his name now, sorry, but I am a fan of fast API. I'm using it as an example in my book. And fast API allows you to use by Dante to create the signature of the endpoints of your API. And then it generates automatic open API documentation. So that's really great. And it's a great use of type hints at runtime. Okay. There are some very large scale users of type hints. Like, you know, those first three companies Dropbox Facebook and Google made a huge investment to use type hints internally. And they developed different tools like my pie was developed by Dropbox, Pyree, my Facebook and pi type by Google. Those are three standalone type checkers that you can download and use. They are open source. The only problem is they are usually lagging a little bit behind. Okay. And my type now only supports Python tree. Seven, I think. And my pie supports Python tree. Eight mostly, I think a little bit of Python tree nine doesn't support Python tree 10 yet. But anyway, those companies also discovered, I don't know, maybe there are people in the audience that are still maintaining code bases in Python 2.7. I know the reality is that, you know, there's no more updates to Python 2.7, but there's a lot of code running using it. And they discovered Dropbox Facebook and Google that type hints are extremely useful to help migrating from Python 2.7 to modern Python. And the way to do it is to use a syntax comments. I mean, a common syntax that is also possible to use with Python 2.7 and the type checking tools understand. And after you migrate the code, you can run a utility that converts those comments into type hints with the modern syntax. Okay. So there are very, very large companies with literally millions of lines of Python code using type checkers and type hints in production. Okay. And of course, the companies that make ideas they benefit a lot from type hints because it makes their ideas work better. But also Soft and JetBrains are both companies that have invested a lot in this and have their own type checkers. Okay. Every year there's a Python developer survey, the 2020 edition announced that a review that, as you can see here, the people who responded that survey said that at least sometimes they use optional type hinting. It's interesting to note that 89% said they use auto-completion. And auto-completion is greatly helped by the presence of type hints, even if not in the user's own code, maybe in the code of the libraries that they use. And other similar tasks that people are using a lot, like code-linting and writing tests, as well as optional type hinting, those are all things that help with code quality, right? So now let's talk about the four modes of typing. First, I want to talk a little bit about duck typing. So duck typing is a concept that was popularized initially, I think, in the Ruby community. But according to Wikipedia, this guy, Alex Martelli, who was a friend of mine and was one of the reviewers of the first edition of my book, Alex Martelli, according to Wikipedia, is the first person who used the duck metaphor to talk about typing in a mailing this message in the year 2000, 21 years ago. So what he wrote was that don't check whether it is a duck. Check whether it walks like a duck, walks like a duck, et cetera, depending on exactly what subset of duck-like behavior you need. So that's the essence of duck typing. The idea is that you don't use instance checks. What you do is you take an object and you check whether the object has the method that you need. And then if the object has the method that you need, it doesn't matter what is its class, what is this, you know, the superclasses. The only thing that matters is that the object has the method that you need, right? This is the essence of duck typing. And it's the essential typing mechanism of Python, of small talk, the language where the concept of object-oriented programming was named, of JavaScript and of Ruby. So it's an important typing concept. It's very flexible. So if you're taking to account duck typing, then it's no longer just a matter of static checking and runtime checking. There's another dimension which is how the types are checked. So with nominal types at the bottom, which is the tradition in static typing. So static typing is static checking with nominal types. And what nominal types mean is that all types are explicitly declared somewhere. And even there are some modern languages with static typing that now have something called type inference that allow you to omit some type declarations. But type inference always depends on explicit type declarations somewhere in the code, right? So that's one aspect. The other aspect, the top of this graph is structural types. So that means that what determines if an object is suitable is not a declared type, but the structure of the object, the attributes and the methods that the object has. Any object that matches an expected set of methods is good enough. That's the essence of structural types, right? So if we want to simplify and leverage our experience with other languages, at the bottom left we have the Java style, at the top right we have the Python style, okay? Now, there is also Goose typing which is another term invented by Alex Martelli that did not catch on. But this is, I won't have time to talk about that, but this is a way of using nominal types at runtime using ABCs which are abstract based classes in Python. So Goose typing is useful in certain contexts, not as useful as static typing and not as useful as duck typing, but it's something that exists in Python and we use it sometimes. And three years after static typing were, type hints were introduced in Python, we have now since 2018 protocols, also known as structural subtyping, also known as static duck typing. So static duck typing is a way of enabling the check of structural types statically, meaning it's a way for us to declare expected structural types so that type checkers and IDs can verify them just looking at the code statically, right? I put here some languages to exemplify other languages that use those different typing modes, right? So let me get a little sip of water while you look at this graph. So as you can see Python and TypeScript are the languages that appear in all four quadrants. Python initially was only on this quadrant, then it adopted Goose typing, then it adopted static typing, and then it adopted static duck typing. TypeScript has all four modes as well. As I mentioned before, small talk is a language that is basically is only duck typing in small talk, but Go, and Java on the other hand is only static typing, right? But Go is interesting because Go is a statically typed language that supports Goose typing because it has type assertions, which is a way of testing types at runtime that is frequently used in Go. And it also has static duck typing. The concept of interfaces in Go is similar to the concept of protocols in Python. Actually, the opposite, right? Because Go came out first with this. But I'm going to explain how this idea of protocols work right now, okay? So let's talk about the central role of typing protocol. So how do you declare a protocol? You import from the typing module this protocol class that exists in Python 3.8, okay? And then you declare a class, a subclass of protocol, okay? So this is like an interface declaration where I am giving, I'm declaring an interface called, but I'm going to call it a protocol because this is what it is. So I'm declaring a protocol called text reader. And the protocol has a read method that returns a string, okay? And the three dots here are part of the syntax. You may have seen sometimes in Python the pass keywords. It is used sometimes, for instance, to declare an abstract method. You put pass in the body because Python requires something in the body. We don't have the braces to close. An empty body has to have something in it, right? So people use pass usually. But now the convention for protocols is to use three dots, okay? This is syntactically valid in Python. And it means that I'm not going to explain what the implementation, I don't care about the implementation of reads. All I care is that read takes the receiver objects and returns a string, okay? It doesn't matter how it's implemented. And then here we have a function called run file that takes an argument called source file. And I declare that the type of source file is a text reader. So what I'm saying here because of, and notice that these two things come together and this is on purpose, okay? This is not just a didactic example. This is something that would appear in real life code. It is actually part of a real life code. Anyway, so what this does, the fact that I declare a protocol and then I use it, is the essence of duck typing. What I'm telling whoever is going to write, whoever is going to call my function run file knows that they need a text reader. And then they will look here and say, okay, anything that provides a read method that returns a string is a text reader. It doesn't matter what the class of the thing is at all. It only matters that the thing implements a read method that returns a string. So because this is written in the source codes, this declaration here, and this declaration here, that means that tools statically an IDE or type checker, a command line type checker, can verify when I call somewhere else in my code the run file, the tool can check that the thing that I'm passing as an argument to run file has a read method that returns a string. So that's duck typing exactly how Alex Martelli defined it, but then in a way with a protocol declaration and a type hint, it's done in a way that a tool can check it. So that's the idea of static duck typing. It's duck typing done with declarations and codes and type hints that allow a type checker to verify. Okay. For instance, one of my small contributions to typeshad was that I discovered that there is a function in the partner standard library called median low. And so what is the median? The median of a series is you sort the items in the series and you pick the middle item, right? Median low is a variation of that idea for situations where when you have an if you have an odd number of items, the median is the middle item. So that's easy. But if you have an even number of items, median low returns the one to the left of the middle and median high returns the one to the right of the middle. So that the value that you get is a value that exists in the sample. It's not an average of the two. All right. Anyway, so this function was declared last year on typeshad with this annotation. Median low requires an iterable of number. And number, oh, and it returns a number. Okay. And number was declared elsewhere in the file as an union of infloten complex. Okay. Or something like that. But the fact is there were two issues. First, the declaration that existed overlooked the fact that there are other numeric types in the world, even in the standard library, we have decimal and fraction, which are numeric types in the standard library. And also there are numeric types in NumPy and other tools, right? So that was one problem. The second problem of this type hints was that it ignored the fact that you can actually pass a list of strings and get the median value. But is that useful? Yes, it's useful. For example, let's say I have a class of students and I want to split the students in two teams. So I can take the list of the student names, sort it, and take the median row. And then it comes out, let's say it comes out Maria. So I say, okay, everybody in alphabetical order up to Maria is team A, everybody else is team B. Okay. So you can use median row in other situations that don't involve numeric types. And the implementation in the standard library supports non-numeric types. But the declaration on typesheds was generating false positives. See where it says here, false positive, because it was flagging codes as error, but code that would work because this declaration was too strict. So the way to solve this problem was to create a new protocol that I call sortable. And the sortable protocol has just one method, which is the underscore, underscore, LT, underscore, underscore. Because of so many underscores, we call such methods, Dunder methods. Dunder is short for double underscore. So Dunder LT is the method that implements the less than operator in Python. And the less than operator is the only thing that Python uses to sort things. So anything that implements the less than operator by implementing the Dunder LT method can be sorted. And therefore, can be used as an item when you call median row. In order to use the protocol, I also had to use a type var. I don't have time to explain this here. But basically, this declaration is saying that sortable T is a type variable bound to this protocol, meaning that. So in essence, this declaration on 9.16 here is saying that median row accepts an iterable of things that are sortable. And it will return a thing that is sortable. Okay. So after I submitted this pull request for type shed, the maintainers recommended that I change the name of sortable to a new name called supports less than, which is a convention that the Python standard library is adopting for protocols. When the protocol declares a single method, often the name of the protocol is supports that method. So they would call this, they would call supports reads instead of text reader. It's a convention that some people are adopting. Anyway, I renamed the sortable protocol to supports less than. And then then I realized that given the supports less than protocol, we could enhance other annotations. Right. I submitted fixes for this sort for max for min and for the sorted and median low and median high functions. And later other people contributed other fixes, other enhancements to type shed using supports less than. So now there are 14 different functions in the Python standard library that use this protocol. Okay. All of these functions before had type hints that could not, that did not address all the cases. Some of them were too strict, like the example of median low that generated false positives, and some of them were too open that generated false negatives. Okay. They could only be fixed when we started using a protocol. And that's because protocols support type support duct typing. And duct typing is part of the nature of Python. It's used in many places in the standard library. It's simply impossible to annotate the standard library and also impossible to annotate very important Python projects like the request library, like jungle, etc. If you don't have protocols, you can't properly annotate a lot of Python codes. So that's why I think that protocols were a very important addition to the type hinting system in Python. So I strongly recommend that you use typing protocol to build Python APIs. Okay. It allows you to support duct typing, which is the essence of Python. It allows you to follow the interface segregation principle. Remember, there's a solid principles. And the I is the interface segregation principle. And what the principle says is that client code should not be forced to depend on methods it does not use. So when I say that in this example, my code only requires that the source file implements a read method that returns a string, I am really using the interface segregation principle. I am not requiring the users of my code to provide a whole interface when I only need one of the methods. The interface segregation principle is one of the principles that helps reduce the coupling between parts of the system. It enhances flexibility. It makes code easier to test because it's easier to mock. And so it's an important principle. And typing protocol is something that supports that principle very well. And here's a best practice. When you create a typing protocol, your own protocols, you should prefer to declare narrow protocols. Meaning protocols with one method typically are the most useful. Sometimes two methods. But rarely you should have protocols with more than two methods. Okay. And that's the experience of the Go programming language has more than 10 years now. And for 10 years, they've been using static typing with their interface system. And they've learned that the best protocols, the most useful protocols are very narrow, usually with one method, sometimes with two, but rarely more. Okay. So now we get to the final part of the talk. Let's talk about typing hints and how to address them. Okay. Now I read a very good article called how to misuse code coverage by Brian Merrick. This is a very good article that I really recommend. But this is not a quote from that article. This is a misquote. In the article, Brian Merrick wrote, type coverage is only used, no, not type testing coverage, you know, testing coverage statistics are only helpful if they are used to enhance thoughts, not replace it. And here I'm using that message to apply to type hints. Type hints are only useful when they are used to enhance thoughts, not replace it. Right. Now, while I see a little bit more of water, consider this scenario. I think most of us would hate a programming environment that would refuse to build a program unless there was 100% test coverage. Right. Because we know that it's okay when we have 100% test coverage. It's not a problem. What is a problem is when you decide that all code must be tested. Because some code is sometimes very hard to code to test, even if the implementation is not difficult. It may happen that the testing is difficult. And also there's also code that is so simple that that is not worthwhile to test. You know, so usually at ThoughtWorks, ThoughtWorks is a company that is a pioneer in agile methods. Martin Fowler, our chief scientist was one of the people who wrote the agile manifesto. So we understand, you know, automated testing a lot. We've been doing it for more than 20 years. And we know that aiming for 100% test coverage is not a good idea. And I think that it's also not a very good idea to aim for 100% type hint coverage. Okay. And I'm going to explain why. First of all, it's not a type, it's not a silver bullet. Okay. You're going to find that you're going to have false positives and false negatives. The static type checking ecosystem, the tools and the annotations themselves are immature. And they are beneath the quality of Python itself. Right. If you think that you're going to eliminate bugs with type hints, just think again. Because first of all, some really simple data constraints such as the quantity must be an integer greater than zero. You cannot express that in a type hint, not in Python, not in Java, not in most statically typed languages in the world. You also cannot say that the airport code must be a string of length three. You cannot say in a type hint that the email address must be a string, but it cannot be empty. So there are some very simple constraints that I wish we could do with type hints, but you can't. Yeah. Those require something called dependent types that is a very sophisticated thing that only experimental languages use. Okay. And the third point is that type hints are generally unsuitable to check business rules. Right. You could also say that those three examples that I gave before, quantity, airport code, and email are sort of business rules. Anyway, type hints are very bad for testing, for checking business rules. Okay. So there's another thing. Like I said, the tools are not perfect. This is a bug that appeared. The bug was filed on type chat, but actually it has to do with a MyPy. And then this guy who is the chief maintainer of the Microsoft type checker said that the problem is actually a bug or a limitation in MyPy. And then he talks about joint operations with types in the constraint solver and union operation. And I am saying that because I want to introduce a theme. Okay. And the theme is complexity. That's another downside of static checking. Okay. There are, you know, Python grows mostly with adoption of Python enhancement proposals, right, which are documents like the Java JSRs or the internet RFPs. They are documents where people say, hey, we think we should have this new feature in the language. So somebody writes a very rigorous spec of how the feature should work and then the maintainers, the Python core developers discuss and adopt it or reject it. Anyway, there are now 22 PEPs just about typing. Okay. And that is complexity. There are no other parts of Python that have even more than three or four PEPs. And I don't think this is the final list. This is the list as of today, not as of today, as of a few weeks ago when I updated it. But I think people are going to come up with new ideas for typing. So it's a complicated topic. Okay. Another example of complexity. The max keyword, not keyword, the max built-in function is easy to use. I've taught Python to lots of people. Nobody ever complained that they don't understand the max keyword. You can pass it an iterable of items or you can pass several arguments and it will return the largest item or the largest argument. Okay. But it has some optional arguments. Somebody discovered that this was generating a false negative. Okay. And at the time when it was generating a false negative, the type hints for max were already very complicated. I don't have time to explain this. I just want to mention that the add overloads decorator is used when you need to write more than one signature for a function so that the type checker can understand it. Okay. This was already complicated and not good enough to catch basic errors. I submitted a batch to improve that with the help of jelly, and our solution has six overloads. So that's very complicated, right? Most of the time I agree that type hints help with readability. But there are examples like this one where type hints just hinder the readability, right? And here's a curious thing. In order to develop that, because the max function is written in C, in order to write those type hints and test them, I wrote max in Python with the same functionality of the one in the standard library, right? And if I put together the 20... See, my implementation of max is 26 lines of code. But all the things that I need to do to annotate, I need to define a protocol, I need to define three type variables, I need to import stuff, and then I need to write six overloads. That's 29 lines of code, right? So it's an example where there are situations where there is a mismatch. And my main point with this example is this. Imagine if when Python was initially developed, type hints existed and were mandatory. Nobody would have written max like it is. And I like max as it is. I like the fact that max is flexible and powerful, right? But if type hints were mandatory, just the fact that somebody would have to write this or this to annotate it would probably scare people away, right? So instead of our nice, powerful, flexible max function, if there were mandatory type hints, probably we would have six different max functions that you'd have to memorize. Okay? So the thing is static type trackers can't handle the expressive power of Python. My time is running up, so I'm not going to read this slide. I'm going to publish it later on speaker deck. So speaker deck.com slash my name, I'm going to put those slides there. Okay? The fact is Python is more powerful than you can express with type hints. Sometimes the type hints are too complicated and sometimes it's just impossible to annotate Python code, okay? So but let's talk about good sense, the last part. Any code that you can write in Python, you can test in Python, okay? So although type hints are limited, tests are not limited because tests are also written in Python. Bruce Sackle, who is now a friend of mine, is a guy who wrote several books about statically typed languages like C++, Java, Scala, Kotlin. When he learned Python, initially he thought that it was not possible to write robust programs in Python, but then he discovered that it was so easy to write tests in Python because of dynamic typing, that it was actually possible to write robust code in Python if you had adequate unit tests, okay? So compared with unit tests, type hints can help you detect a different and smaller set of bugs. Static type checking complements but cannot replace automated testing, okay? So Python is a dynamically typed language with powerful abstractions and advanced metaprogramming features and that's why we like it, okay? Teams can only avoid the downsides of type hints if they are not mandatory everywhere. For instance, if you are using MyPy, there are options like the ones on the top of the slide that are helpful to use type hints gradually and there are other options of MyPy that if you adopt them, they are going to force you to annotate everything and otherwise they're going to be generating warnings of the time. So carefully think about the configuration of MyPy so that it helps you to use type hints most of the time but also allows you to not use them sometimes, okay? Instead of adopting options that will generate warnings every time that you are trying to cope with type hints, okay? Static typing, the main takeaways of the talks. Static typing is valuable in certain contexts. Please use protocols to enable Pythonic APIs, okay? Particularly if you're developing libraries or frameworks that other people are going to use, it's important that you use protocols so that you give more flexibility to the users of your API and it's easier for them to comply with the typing requirements of your API, okay? And don't make type hints mandatory everywhere. Developers should be free to leave portions of the code without type hints to avoid the downsides and limitations, okay? So being optional is not a bug or a limitation of Python type hints. It's the feature that gives us the power to cope with the inherent complexities, annoyances, flaws and limitations of static types, okay? So thank you very much. I don't know, I don't have anything to do with Sunday morning in Brazil so we can have Q&A or we can have Q&A in Zulip. Kalyan, how are we going to do Q&A? So yeah, we have a couple of questions so I'll quickly read out for you. Okay. So at what point should you suggest people should think about adding types in your project? Is it regarding or adding types to choose code base? What are the efforts for them or the new ones that will join? Yes. This is an excellent question, okay? So type hints are useful for onboarding people. If the type hints are already there, people are going to find it easier to work with the code base. But if the type hints are not there adding type hints also helps with onboarding. But how to do it? I talked with Martin Fowler, I mentioned him before about this and he made a very interesting suggestion. We discussed about this. So the thing is the parts of a large code base that will benefit more people if they have type hints are the internal APIs or the public APIs that are more widely used in the system by internal or external users because then everybody that uses that API is going to benefit from the type hints. So that's one idea. Maybe you can prioritize type hinting the more public interfaces, the parts of your code base that are called by more parts, more of the other parts. However, there's a downside of this approach, which is if that's the first code that you annotate, then maybe you're going to not do a great job of annotating it. And then you're kind of making your beginner mistakes exactly in the part of the code that is affecting more people. So maybe a best solution would be to pick some modules of the system and go deep into it with type annotations so that people can practice doing that and understand the limitations and the potentials, the upsides and the downsides, the pros and cons. And then after some people have experienced annotating deeply a part of the code, then they can start annotating more public interfaces. But the thing is, in reality, we are always forced to usually work with new features, add more codes, add more features. And so it's the same thing sort of with unit testing. Sometimes you don't have the opportunity to do a lot with the legacy. You adopt these practices in new code more often. That was a very good question and I hope. So there's no easy answer. That's the thing. Thank you. So here is the last question. Is there a standard function to check if a type support a certain protocol, like instance, works for subclasses or types? Yes. Very good question. So it's important to understand that protocols are mostly used by static type checkers, right? That's why they were introduced in Python. For runtime type checking within instance, which is the characteristic of loose typing, it is now possible to use protocols as well. There is a decorator called runtime checkable in the typing module. So if you put at runtime checkable on the top of a protocol that you define, then Python will add functionality to that protocol so that instance checks can be made at runtime. And they would work similarly to the way that A, B, C, that test the instance text with A, B, C works. Very good question. Thank you.