posted: February 29, 2020
tl;dr: Dynamic typing if you dare, static typing if you must...
The third in a series of posts highlighting the commonalities of Python and JavaScript.
Another major similarity between Python and JavaScript is that both languages feature dynamic typing, with completely optional static typing. There are some differences in how each language implements static typing, however.
For those who, like myself, worked in primarily statically-typed languages earlier in our careers (such as C/C++ and Java), dynamic typing seems weird at first. We’re used explicitly declaring variables and telling the compiler exactly what type of value will be stored in each variable. This allows the compiler to reserve the exact amount of memory needed to hold the declared type, and to know exactly where in memory it will be located. Without this information, the compiler can’t compile the program.
Python and JavaScript, however, have a completely different memory model (more about this in a subsequent post), which enables dynamic typing. At one point in time a variable can “hold” a floating point number, and later a string, and later an object of a custom class. The binding of the variable name to the “thing” in memory that it is “holding” (or referencing) happens at runtime, not at compile time, and it can change as the program executes.
Why on earth would you ever want to do this?
The simplest case is mildly beneficial but also mildly problematic. Let’s say you’ve prompted the user to enter his/her entire name, which comes into your program as a string. A logical thing to do is to store this string in a variable named name. Maybe you have to display the name the user entered, so you can use name to retrieve it and display it. But later in your program you have to deal with each individual portion of the name, such as the first name and last name. Both Python and JavaScript allow you to do name = name.split(' ') so that name from this point forward contains a list/array of each individual portion of the full name the user entered. You don’t have to invent a new variable name, such as name_split, to hold the list/array. Thanks to dynamic typing, your program will have fewer variable names, especially when you are doing a lot of type transformations.
With dynamic typing don’t have to invent a new name, but maybe you should anyway. It can be confusing for others reading your program to realize that the type of the variable named name has changed. Another programmer might try to modify your code and not realize what the type of name is at the point where the code is being modified, causing an error. The error may not be caught until runtime.
This simple example is not why dynamic typing is loved by so many. The main benefit of dynamic typing is that it allows code to more easily adhere to Postel’s Law, which arose in the early days of the Internet: “be conservative in what you do, be liberal in what you accept from others”.
When writing a function that is passed an argument, Postel’s law says that your function should work across the widest variety of possible input argument values. Dynamic typing allows the input to be any type, with the binding happening at runtime. If your function just needs the input to have a few properties, attributes, or methods, then it can access just those needed items. As long as they are supplied in the input, the function will work, regardless of what other properties are present or what the type of the supplied argument is. This can be incredibly useful when parsing networking packets, implementing APIs, or writing lower-layer services used by higher-layer application code.
In the static programming world, your function is only going to work if the supplied input exactly matches what you specify in advance. Your function is going to be more brittle and more likely to refuse to work as things evolve. The Internet, of course, evolves pretty quickly. It’s no surprise that Python and JavaScript are very popular in Internet applications, as are other dynamically typed languages such as Ruby and PHP. Dynamic typing also enables duck typing, an especially succinct, elegant way of programming
Yet statically typed languages such as C/C++ and Java are still very popular, especially for enterprise-class applications. There’s an argument that, as team size and codebase size grows, enforcing static typing can bring benefits. Forcing programmers to declare all the types that their code accepts provides documentation and clues to other programmers. It allows type mismatches to be caught earlier, at compile time instead of runtime. The type declarations can be used by IDEs to provide hints to programmers as they are entering their code, for catching errors even earlier than compile time.
I’ve not worked on multi-million line codebases, but I have respect for some of the people who have. Python inventor Guido van Rossum recently retired from Dropbox, which has a Python codebase of 4 million lines. In recent years Guido has been involved in the mypy project, the optional static type checker for Python. Microsoft develops large applications, including one that I use nearly every day, Visual Studio Code. They invented TypeScript, which adds static typing to JavaScript.
Mypy and TypeScript do roughly the same thing, and even have some syntactic similarities. As with many common Python and JavaScript features, the Python implementation is arguably more elegant. Starting with Python 3.5, the CPython interpreter allowed (but didn’t require) type declarations. Programmers could choose to put them in or not, and they are just ignored by the interpreter at runtime. Mypy is a separate module that will read the type declarations and provide feedback on type usage. Python developers who want type checking can put in the type declarations and run their code through Mypy or other Python static type analysis tools.
Microsoft didn’t have the luxury of getting the world to move to a new JavaScript runtime that would allow (but not enforce) type declarations. So they invented the TypeScript compiler (a.k.a. transpiler), which takes type-annotated JavaScript, does the type enforcement, and produces a JavaScript output file that can be run. There are other reasons for compiling (or transpiling) code to JavaScript, such as adding in other features missing from the base JavaScript languages. Microsoft’s approach is a pragmatic one for the JavaScript ecosystem.
The result is that, as of now, both Python and JavaScript are dynamically typed languages with optional static typing.