The decision on how to type a language affects everything about the functioning of the language. From variables to general program flow, every part of the language will be shaped around what typing a language uses. There are several different types of typing which can impact a language, but we’re going to focus on the difference between static typing and dynamic typing.
Typing refers to data types and how “rigid” they are. How is data stored and how can it be accessed? How is typing enforced? What are some common misconceptions about typing? All these are concerns and all of these affect which language ends up best for your project.
Static Typing
Static typing refers to when data types need to be static at run time. This means they need to be set properly at compilation and cannot change without a properly defined operation in the language (usually a cast). Compilation doesn’t just mean this is something true for compiled languages either. Many interpreted languages use a just in time compiler or similar technique to compile the script into byte code on execution.
For instance, in C#:
string s = "This is a string";
int myNumber = 35;
double myDecimal = 35.0001;
Each of these variables has a defined type which has defined interactions. You can’t just go and do the following:
int myNumber = 35;
double myDecimal = 35.0001;
int otherNum = myDecimal + myNumber; //this will fail to build
You have to tell the language that you’re going to be working with int throughout the whole thing.
For instance:
int myNumber = 35;
double myDecimal = 35.6;
int otherNum = (int)myDecimal + myNumber; //truncates 35.6 to 35
int otherNum2 = Convert.Int32( myDecimal ) + myNumber; //rounds 35.6 to 36
These operations all have an expected behavior that will be consistent and predictable even though there are different operations which get different results. Casting directly to an int will truncate it while explicitly converting will round. If you’re adding two random numbers together, what specific behavior would you expect? With static typing, you don’t need to rely on guesswork, your explicit casting will affect how the data is shaped.
Dynamic Typing
Dynamic typing refers to when a language is more agnostic to data types until the program executes. A variable is a variable and there are implied casting operations when working with data. Variable types are enforced at runtime instead of at compilation. Many interpreted languages are dynamically typed, but this is not a rule. There is a common misconception that all interpreted languages are dynamically typed.
For instance, in Lua:
#!/usr/bin/lua5.3
local a = 1
local b = 2.3
local c = "cat"
print( a + b )
print( a + c )
This will get you:
3.3
/usr/bin/lua5.3: ./test.lua:8: attempt to perform arithmetic on a string value (local 'c')
stack traceback:
./test.lua:8: in main chunk
[C]: in ?
We can add our numeric types fine, but Lua doesn’t like the attempt to perform arithmetic on a string value. This type of issue would not pop up during run time for a static typed language as it would either not compile, or would segfault when trying to force a string into an int in the case of user assigned data (without error handling). Some languages are even more flexible than Lua, such as Perl:
#!/usr/bin/perl
my $a = 1;
my $b = 2.2;
my $c = "cat";
print $a + $b . "\n";
print $a + $c . "\n";
print $c + 0 . "\n";
print $a . $b . $c . "\n";
This gets us:
./test.pl
3.2
1
0
12.2cat
Perl doesn’t care what type these variables are as they are all scalars. Each conversion is implied by what you are doing. We can treat them as numbers (even $c as “cat” can be a number), or as strings without any implicit conversion. Perl just assumes each operation is intentional even if it makes no sense like adding “cat” to 1. This gets into another spectrum of typing, strong typing versus weak typing.
Strong and Weak Typing
We saw that Lua wouldn’t let us add a string to a number, but had no qualms with different types of numbers. We also saw that Perl didn’t care at all what we put together. C# won’t let us add a decimal to an integer. All of these have differing levels of typing strength. Compiled languages tend to be the most strongly typed, but there is no hard requirement. Some languages try to sit somewhere in the middle, and others like Perl, Ruby, PHP, etc. treat a scalar as a scalar.
Strong and weak typing can affect how error handling occurs. For instance, if you want to get a variable from a user, how do you get that variable and how do you check it? A strongly typed language would want you to collect it as a specific type and would most likely error out if it got the wrong type. So if you ask for an int and get “cat”, your program will probably crash before it can do something crazy with the data. If you use a weakly typed language, it won’t care what the type is so long as it has a way to handle it. The issue gets in that some languages might interpret “1cat” + 0 as 1 (Perl does this). How do you make sense of these operations? It all depends on how you’re handling the project and the complexity of the code.
Which Is Best?
When people start learning about typing, this is the most natural question to pop up. The answer is “it depends”. If you’re dealing with heavily variable data, a static typed language can be a hindrance if you aren’t checking types. The same can be true for a dynamically typed language if you aren’t checking for errors when running. The difference will be where your program breaks down.
Static typed languages will not compile correctly if there’s something wrong, while dynamic typed languages will break down at runtime. Which is preferable depends on how you handle errors, bugs, and how you write and plan your project. Static typing also lends itself to cleaner code for procedural coding which is why many languages use C inspired styles.
I would argue that static typing is better for larger projects as it makes it a lot easier to not something like the following in Perl:
my $importantvariable = 20;
[…]
$importantvariable += $othervariable;
$importantvaraible -= $someothervariable;
[…]
That minor typo which is painfully obvious to the computer is almost invisible to most people, especially after you’ve been staring at a screen for hours. You can turn on “strict” in Perl and make it enforce typing. For instance:
#!/usr/bin/perl
use strict;
my $a = 1;
my $b = 2.2;
my $c = "cat";
print $a + $b . "\n";
print $a + $c . "\n";
print $c + 0 . "\n";
print $a . $b . $c . "\n";
print "1cat" + 0 . "\n";
print $d . "\n";
This gets us:
./test.pl
Global symbol "$d" requires explicit package name (did you forget to declare "my $d"?) at ./test.pl line 15.
Execution of ./test.pl aborted due to compilation errors.
Not all languages offer these types of features, but this would prevent some of the errors that dynamically typed languages can allow because of a minor typo. This also makes the language more practical for larger projects.
I prefer something with stronger typing and more static typing for larger projects (>20,000 lines) since it makes maintenance much easier. For medium projects (5,000 to 20,000 lines), I tend to go with the tool which makes creation easiest. I tend to end up with something like Perl or Lua with a heavily C inspired style because they’re easiest for me, unless I’m working with a team. Smaller projects will depend on the use case and really don’t matter much unless they’re business essential or are going to be passed on.
Not All Languages Are Created Equally
When programming, a language is a tool. You can be great at a language, but you don’t use a hammer on a screw. Each language has its own strengths and weaknesses. Consider how the typing affects what you’re doing and the workflow you work best with. Take into consideration the program’s use case as well.
Strong typing and weak typing are on a different axis to static typing and dynamic typing. There is often a correlation between the typings, but there doesn’t have to be. Static typing helps prevent issues from making it to runtime, but it comes at the expense of more verbose error handling. Dynamic typing can make things more flexible up until runtime. Strong typing forces variables to be explicitly cast or converted to be combined, while weak typing allows on the fly conversions without having to think about it.
Each has its own merits, but each also has its own folly. Pick the language based on its strengths for what you’re doing rather than becoming wholly committed to a given language for the sake of using a given language. By learning to leverage the strengths and minimize the weaknesses, you can use typing to its fullest.