Introduction to Data Types: Static, Dynamic, Strong & Weak

    Tim Hurd
    Tim Hurd
    Share
    This article explains what data types are, what is meant by the terms “static”, “dynamic”, “strong” and “weak” when we talk about data types, and why should we even care.

    What Are Data Types?

    In programming, a data type is what we tell the computer the type of data it’s dealing with, e.g. a string, number, or object. When defining a variable, a computer needs both the name and the type of data before it can store and process it. This way it knows much much memory to set aside, how to access it and how to change it. You might find it easier to flip around the term and think of it as “the type of data” we’re dealing with. For example, in JavaScript, let name = "sitepoint"; creates a variable called ‘name’ with a type of ‘string’.
    let name = "sitepoint";
    console.log(typeof name);
    // "string"
    
    Each programming language has a different way of handling how it assigns data types (static vs. dynamic) and how flexible (strong vs. weak) they are when trying to change them. You might have read conflicting information about “static” vs “dynamic” data types, as well as “strong” vs “weak” data types. They’re not the same thing, and a language can include a combination of static/dynamic and strong/weak data types:
    • Static vs. Dynamic defines how a language expects you to declare data types. Static typed languages require explicit definition of a data type when they create a piece of data (e.g. variable, parameter, return value). Dynamic languages are the opposite and can infer, or at least try to guess, the type that we’re using.
    • Strong vs. Weak defines how flexibly a language allows operations between data types. For example, strongly typed languages will not allow you to add a float to an integer, without you converting it first, even though they are both numbers. On the other hand, a weak language will try its best to accomodate what the programmer is asking and perform these operations.
    There is no best
    option with choosing static vs. dynamic or strong vs. weak. A strict language will ensure consistency and reduce the amount of errors you make in your code. As a trade-off you might find yourself writing more verbose code and defining and converting types that may seem obvious to the human eye.

    Why Should We Care About Data Types?

    Every programming language has a data type system. Without a type system, computers wouldn’t know how to represent the data in our programs. They wouldn’t know how to take this type of data and add it to this other type of data or even how to store the data. By specifying a variable as an integer, the computer knows how many bytes it needs to represent the value and, more importantly, how it can perform operations with it. Adding two integers together is a different operation from adding together two strings. The only way the computer knows how to handle the data is by knowing the types of data it’s dealing with. You can begin programming without knowing much about the underlying type systems at play. That’s part of the beauty of these higher-level languages. But understanding the types of data you’re dealing with, and how best to represent the data you’re working with, brings huge advantages, such as those listed below.
    • You’ll have more efficient programs that make better use of memory and storage. By knowing that an array of integers occupies less space than an array of doubles can lead to kilobytes or even megabytes of savings when dealing with very large arrays in memory or on the hard disk.
    • It will help you decipher debugging messages and gain a better understanding of problems related to data types. When the program complains it can’t add two numbers because one of the numbers is a string, you understand why. Learning this fact will help you avoid making the mistake of trying to add a number to a string to begin with.
    • Once you know how types work, you can be like Neo from the movie The Matrix and know how to bend the rules. You’ll know when adding an integer to a character how you can get another character and why that works.

    Static vs Dynamic Data Typing Systems

    Static data typed languages are those languages that require the programmer to explicitly define a data type when they create a piece of data (be it a variable, parameter, return value, and so on). Typically, these types are also fixed as being that type for the lifetime of the program, and they don’t change their type. Let’s take a look at an example:
    int myNumber = 42;              // integer data type
    string name = "Rocky Balboa";   // string data type
    final double PI = 3.141592;     // double data type
    
    // Function takes two integer data types, returns an integer data type
    public int add(int a, int b) {
        return a + b;
    }
    
    This example above shows a few variables being defined, and an example of a function that adds two numbers together. As you can see, we are explicitly telling the language (in this case, Java) that we’re dealing with integers, strings and doubles. Without these hints to the compiler, the compiler would not know how to treat myNumber
    . This is just a name that makes sense to us, not the computer. Some languages that are statically typed include Java, C#, C++ and Go. But these are just a few of many. Let’s contrast this with a dynamic data typed language. Below is an example:
    $myNumber = 42;           // integer data type
    $name = "Rocky Balboa";   // string data type
    $PI = 3.141592;           // float data type
    
    // Function takes two integer data types, returns an integer data type
    function add($a, $b) {
        return $a + $b;
    }
    
    So, where did all the types go? In this example above, we see that our variables in PHP, a dynamically typed language, don’t explicitly say what types of data they are. If we’re not telling PHP the data types, how does it know? Well, it guesses based on the value being assigned to it. It can correctly guess that $myNumber is an integer because the value 42 is an integer. What about the function? It too makes a guess based on the values passed to it. This means that add() could take two integers and return an integer, or it also could take two floats and return a float. The types are inferred and can even change during runtime. We could later, in the same program, say that $myNumber is equal to Tom
    and it will let us switch the variable to a string. A few of the many languages that are dynamic include JavaScript, PHP, Python and Ruby.

    Why Would You Prefer Static Over Dynamic or Vice Versa?

    In the case of static data typed languages, by explicitly telling the compiler up front the types of data you’re dealing with, it can catch common mistakes and errors in code long before deployment. If you define one value to be an integer and another to be string, the compiler can catch an addition error during compile time and won’t let you finish building the program. This is good in that the earlier you catch an error, the stronger your code will be, and the less it will cost you and your clients to fix it. It’s much easier to fix things early than later after deployment. So static is the way to go right? Well, the tradeoff is that you have to explicitly define everything before you use it. You have to type more code, you have to know the type of data you’re dealing with beforehand (not always something you know) and you have to know what’s going to happen in your operations. You have to know that 1 / 3 is going to give you 0 and not .33333 and things like that. Dynamic languages give you added flexibility in this area. They’re often described by programmers as being “more expressive”. In PHP, for instance, you’ll get .3333...
    as you might expect. However, the problem is that if the interpreter makes a wrong guess in the data types, you have to know about it. Otherwise it can sneak by. Since we can’t catch everything, code in dynamic languages tends to be a bit more error prone and brittle. Data types in these dynamic languages are typically determined at runtime. This makes it hard to catch many errors until they reach a production environment. It may work fine on your local development machine, but the production runtime environment could be slightly different, yielding some different guesswork by the interpreter. JavaScript is one language that is considered dynamic. With the introduction of TypeScript, a superset of JavaScript, programmers introduced the idea of explicitly declaring data types for variables in order to make the language more static. As JavaScript’s popularity has grown — even beyond the browser with tools like Node.js — programmers wanted to add the benefits of static data typing to take out some of the wrong guesswork JavaScript does when dealing with data types. JavaScript is notorious for some of its bad guesswork when dealing with data and its types. This is an example of making JavaScript, a dynamic language, into something more like a statically typed language to catch errors early and lead to healthier code. This is all the more important given that JavaScript is making its way into server-side applications with the help of Node.js. In short, static data types give you a strict environment and typically yield stronger code. Dynamic languages give you flexibility and the ability to write code faster, but can lead to more error prone code if you’re not careful in checking your types.

    Strong vs Weak Data Typing Systems

    Strong/weak data types are how a language handles the values it operates on. Will the language quietly make some assumptions when working with the data types and help you out, or will it just stop and complain that it doesn’t know what to do? Let’s take a look at an example of how this works:
    int main() {
        int a = 5;
        std::string b = "5";
    
        // Houston, we have a problem!
        std::cout << (a + b);
        return 0;
    }
    
    In this C++ example, we’re trying to add an integer and a string together. Yes, the language is statically typed, but it’s not trying to cover for the programmer by making b an integer so that it can add two numbers together. It just flags the issue right away and gives up. This check is done when we attempt to compile the program (or sometimes by an IDE as you write it). Here, we’re trying to use the type in a way that is counter to its definition of being a string. Strongly typed languages include C#, Java, Go, Python and C++ to some extent, and they all would flag something like this. Now C++ has ways to weaken its strongly typed system, but that’s beyond the scope of this article. We’ll cover weak data types and then talk about strong/weak together and how things aren’t as clear cut as static/dynamic typing. A weak data typed languages attempts to help out the programmer as it carries out its operations. Let’s take a look at JavaScript and see how it might do a similar operation to what we did in our C++ example above:
    const a = 5;
    const b = "5";
    
    console.log((a + b));
    
    If you know anything about JavaScript and its quirks, you know that the code above will work without fuss. It won’t point out anything to the programmer. But it won’t log 10 to the console as you might expect. You’d think it would see an integer and a string and go “Whoa, wait a minute here, I don’t know what to do with this!” Instead, JavaScript attempts to coerce, or convert, one of the values to be like the other, do the calculation, give a result and move on. Here the result would be "55" since it converts the value of variable a into a string and then concatenates them. The result would then be a string data type. As you can see, the strength of a language is how strongly it attempts to use its types to make sense of the programmer’s intention and moves on. Using these terms, we can say a language like Python, which is dynamic, is also strongly typed. You don’t need to explicitly define a type when you create the value (dynamic part), but if you try to and then use that type in a way that it doesn’t expect, it will immediately flag the issue and quit (strong typing).

    Why Would You Prefer Strong Over Weak or Vice Versa?

    Strong languages are rigorous languages. Again, they make sure they know exactly what the programmer intends to do. If an error occurs, it’s more often than not an error by the programmer not understanding the operations. These errors also potentially point the way to a lack of understanding about the problem. If you’re trying to add 5 the number to "5" the string, then perhaps you don’t realize how that’s not going to make sense to a computer. It forces you to come to the truth of the operation and makes you explicitly tell the computer what you want to do (usually with some form of conversion/casting mechanism). This tends to lead to stronger and less error-prone code in production, but adds time and hoops to jump through during development. Weak languages, again, lean more on the side of flexibility and expressiveness, by taking away the strict rigor of a strong language and allowing the programmer to get their code up and running. But the down side is that the computer makes assumptions that the programmer may not have intended. JavaScript, a weak typed language (that also happens to be dynamic), again was beefed up with TypeScript to make it stronger. TypeScript’s handling of data types allows a programmer to write JavaScript using explicit types and to gain the benefit of a strongly typed language. It catches many errors during compile time and helps keep vague JavaScript assumptions from reaching production systems. But again, this is at the cost of being more formal and rigorous with coding format during development. Even code editors that know TypeScript can flag the errors as you write them. VS Code is one great example that does this.

    Degrees of Strength

    We’ve now looked at strong and weak typing. It’s important to note that, unlike a clear-cut line that exists with static/dynamic typing, languages can show varying degrees
    of strength or weakness. This puts languages on a spectrum. This is why you find some articles saying that C++ is weak while others say that it’s strong. It’s relational. What makes it a spectrum is that some languages offer tools to help with conversions and changing of types on the fly. Some use things like pointers. This is why you may hear people saying that Java is more strongly typed than C or C++, when obviously C++ is strongly typed in comparison to JavaScript. I find it not so crucial to understand every nuance of what makes a language strong or weak. As long as you know some of the basics and can tell the difference between levels of strength, you’ll be in good shape when picking a language for a given project and its requirements.

    Choosing Which Style Fits Your Project

    There are many reasons why you might choose one language over another for your next project. Type systems tend to fall low on most people’s list, trumped by bigger considerations such:
    • the language a developer is most comfortable with
    • which language offers more features that fit the project scope
    • the tools that are available for faster development
    But when it comes to looking at type systems, keep in mind that if you’re working on a mission critical project that needs to be memory efficient, stringent, and where errors can be caught early, you might want to look at something statically typed. If the language shouldn’t make assumptions and requires explicit instructions to help with critical algorithms, also consider something that’s strongly typed. These are languages you tend to find in “AAA” rated games, for example. However, if you’re looking to get something out fast and with flexibility, which affords some expressiveness by the programmer, then dynamic or weak typed languages might be a better fit. Or you might prefer languages that mix the two. This is partly why a language like Python is chosen by many.

    Conclusion

    This article has attempted to cover the introductory differences between static and dynamic type systems and also the differences between strong/weak type systems. We’ve talked about how they compare, why you might choose one over the other, which languages fit into each of these systems, and how you might use these differences to choose the language for your next project. I hope you’ve found this article informative. If you take away only one thing from this article, let it be the idea that static doesn’t necessarily mean strong and dynamic doesn’t necessarily mean weak. Languages can exhibit various combinations of each. In the case of strong and weak typing, you can have varying degrees of strength in relation to one another. Good luck on your next project and thanks for reading!

    Frequently Asked Questions (FAQs) about Static and Dynamic Typing

    What are the key differences between statically typed and dynamically typed languages?

    Statically typed languages are those where variable types are checked at compile-time, meaning before the code is executed. Examples include Java, C++, and C#. On the other hand, dynamically typed languages perform type checking at runtime, i.e., while the code is being executed. Examples include Python, Ruby, and JavaScript. The main difference lies in when the type checking occurs and the flexibility and safety each approach offers.

    How does static typing contribute to code safety?

    Static typing contributes to code safety by catching errors at compile-time. This means that many potential issues can be detected and fixed before the code is run. It also makes the code more predictable and easier to debug, as the types of all variables are known in advance.

    Why would a developer choose a dynamically typed language?

    Dynamically typed languages offer more flexibility as they allow you to change the type of a variable at runtime. This can make them easier to use for certain tasks and can lead to more concise code. They are often used for scripting, rapid prototyping, and in situations where the specific types used are not known until runtime.

    Can you give an example of static typing and dynamic typing?

    In a statically typed language like Java, you might declare a variable like this: int x = 10;. The type of x is declared as int and cannot be changed. In a dynamically typed language like Python, you could write x = 10 and later change it to a string with x = "hello".

    What are the performance implications of static and dynamic typing?

    Statically typed languages often have a performance advantage because they allow the compiler to make optimizations based on the known types. Dynamically typed languages, on the other hand, require additional checks at runtime, which can slow down execution.

    How does static typing affect code readability?

    Static typing can make code more readable by making the types of variables explicit. This can make it easier to understand what a piece of code is doing, especially in large codebases.

    Are there languages that support both static and dynamic typing?

    Yes, some languages, such as C# and Python, support both static and dynamic typing. These are known as “optionally typed” languages. They allow developers to choose the best approach for their specific needs.

    What are the trade-offs between static and dynamic typing?

    The choice between static and dynamic typing often comes down to a trade-off between safety and flexibility. Static typing offers more safety and can lead to more efficient code, but it can also be more verbose and less flexible. Dynamic typing offers more flexibility and can be more concise, but it can also lead to more runtime errors and can be less efficient.

    How does type inference work in statically typed languages?

    Type inference is a feature of some statically typed languages that allows the compiler to infer the type of a variable from its value. This can make statically typed languages more concise and easier to use, while still maintaining the safety benefits of static typing.

    Can you mix static and dynamic typing in the same code?

    In some languages, you can mix static and dynamic typing in the same code. This is often done to get the benefits of both approaches. For example, you might use static typing for the core parts of your code where safety and performance are critical, and dynamic typing for parts of the code that need to be more flexible or where the types are not known until runtime.