The previous article in this series (“Variables Defined“) touched briefly on the concept of data types. In this article, you’ll look at data types a little more in depth and examine why they are important to programmers.
Two of the most important concepts related to types are type checking and strong versus weak typing. Type checking is ensuring that the data types used match the constraints of the language. For example, type checking makes sure that your code isn’t trying to stuff string data into an integer data type. There are a couple of different methods for checking for mismatches. Some languages to use static typing. This means that your types will be checked at compile time and that no potential type mismatches will be allowed there. One frequently cited advantage of statically typed languages is that they run faster because the types have already been checked at compile time and there is no ambiguity over the type at run time. Another advantage is that, the more power types have, more are constraints placed on them by the language and the type checker. This means that a programmer won’t overly rely on an unnecessarily powerful type to perform simple tasks.
The other method for type checking is dynamic checking. Dynamic checking is performed at run time. So, the type isn’t actually checked until you bind a value to a variable. A cited advantage in using a dynamically checked language is that the debugger becomes more useful. If you encounter a type error during a debug run, it’s easier to change the type in the debugger.
There is no universal agreement on what constitutes a strongly typed language versus a weakly typed language. Most generally, if a language uses static (compile time) type checking and that type checking can’t be evaded, it fits most definitions of a strongly typed language. An example showing the effect of a strongly typed language is that you can’t perform addition (the + operation) on variables of different types in a strongly typed language—adding a string and an integer makes no sense. A strongly typed language should, at run time, check any variables that will be added and ensure that they have been defined as compatible types.
Weakly typed languages, on the other hand, can allow some operations to pass type checking that a strongly typed language won’t allow. If the language is doing type checking at run time, it will allow you to compile a + b without knowing that a and b are the same variable type if the types aren’t assigned until data is bound to the variable at run time. In fact, some weakly typed languages will go so far as to allow a + b even if an integer is bound to a and a string bound to b (or some other seeming mismatch of types). In this case, instead of performing addition (2 + 2 =4), the language will assume the program intended a different type of operation to be defined by + (called operator overloading) and might define 2 + jim = 2jim.
I’ve mostly used integer and string types as examples here. I’ve used these because for most people, it’s intuitive that a string (“jim”) and an integer (“2”) aren’t the same kind of thing that languages define as “types.” But, there are plenty of other mismatches: performing division on a boolean (true or false only) makes no sense, concatenating two floating points makes no sense (where does the decimal belong?), and so forth. Likewise, as shown above in the operator overloading example, some languages define overloaded operations that aren’t intuitive (letting + mean addition or concatenation). So, these are the examples that are easiest to understand without belaboring infinite possible exceptions in dozens of different languages.
It is important when starting with any new language to know whether it uses static or dynamic type checking. This will determine in part how rigorous your type declarations must be. You also need to know whether operators can or will be overloaded and just exactly what overload operations will be used. All of this is determined on a language-by-language basis.