github linkedin email rss
A Quick Primer on Language Typing
2017-09-23
5 minutes read

When it comes to programming, you’ve probably heard words thrown around like “strong”, “weak”, “inferred”, “explicit” “dynamic”, and “static”.

Here’s a very quick primer, with examples, on what they mean.

Disclaimer

This is only a high-level overview, and skips most of the nuances involved with this topic. It also avoids discussing advantages/disadvantages of different systems.

Dynamic vs Static Typing

Dynamic vs static typing refers to whether or not your language figures out the type at compile-time, or runtime.

With dynamic typing, your language only figures out the type of an object at runtime

With static typing, your language validates the type of an object during the compilation phase.

Inferred vs Manifest Typing

Inferred vs manifest typing refers to whether or not your language requires you to explicitly state the type of your variable.

With inferred typing, your language figures out the type of an object from when it is assigned

With manifest typing, your language requires you to specifically say what kind of type your variable has.

Strong vs Weak Typing

Strong vs weak typing refers to how much your language allows you to mix-and-match different types of variables.

With strong typing, you must ensure your objects are exactly the type you expect (e.g. a string, or an integer); the interpreter/compiler will throw errors if you attempt to, e.g. use a string where an int is expected, or add a float to a char.

With non-strong (weak) typing, your language may not enforce such restrictions. In the case of, e.g. Javascript, the interpreter converts objects so that they match, before attempting to work with them - e.g. if you add an int to a string, it’ll just put the number on the end of the string.

However, in the case of a language like C, the compiler does nothing and assumes you know what you’re doing with the information in memory.

Strong and weak are nebulous terms (unlike dynamic vs static), and cover a broad range of features within a language that actually (dis)allow certain things to happen. While they can be useful terms sometimes (and are used on, e.g. Wikipedia to describe languages), you are better off talking about specific features of a language. (e.g. implicit conversions)

Examples

Python: dynamic, strongly typed

Python uses dynamic typing to detect the type of your variable when it is defined at runtime (e.g. a = 35). Once defined, you cannot mix variables of incompatible types - they must be explicitly converted to match.

a = 35      // detected as int
b = '6'     // detected as str

# Will get "cannot concatenate 'str' and 'int' objects" error
# as strong typing prevents us from combining each as-is.
try:
    print (b + a)
except Exception as e:
    print (e)

# Will get "635" as both can be treated as str
print (b + str(a))

# Will get "89" as both can be treated as int
print (int(b) + a)

Javascript: dynamic, weakly typed

Javascript uses dynamic typing to detect the type of your variable when it is defined at runtime. Once it’s defined, you can then perform operations that use variables of different types

var a = 35;     // detected as type int
var b = '6';    // detect as type string

// Will get "635", as both are treated as strings
console.log(b + a);

// Will get "356", as both are treated as strings
console.log(a + b);

// Can cast, to get "41", as now both can be treated as ints
console.log(a + parseInt(b));

Pascal: static, explicit, strongly typed

Pascal uses static, manifest typing to detect the type of your variable when it is defined at compile time. It also performs compile-time checks to ensure you don’t mix-and-match variables with incompatible types - they must be explicitly converted to match.

program TypeExample;

uses sysutils;

var
    a : integer;
    b : string;

begin
    a := 35;
    b := '6';

    { 
      The following line would fail to compile due to mismatched types;
      as such, it is commented out
    }
    //writeln(a + b);

    { However, these lines *will* compile* }
    // Will output "356"
    writeln(Concat(IntToStr(a), b));

    // Will output "41"
    writeln(IntToStr(a + StrToInt(b)));
end.

Rust: static, inferred/manifest, strongly typed

Rust is statically typed, and supports both manifest and inferred typing. Once defined, you cannot mix variables of different types - they must be explicitly converted to match.

fn main() {
    let a = 35;     // Detected as i32
    let b = "6";    // Detected as &str

    // The following will fail to compile
    //println!("{}", a + b);

    // This will output '41'
    println!("{}", a + b.parse::<i32>().unwrap());

    // This will output "356"
    println!("{}", a.to_string() + b);
}

C: static, manifest, weakly typed (kind of)

C uses static, manifest typing to detect the type of your variable when it is defined at compile time. However, the compiler generally assumes you know what you’re doing when you mix types, so you’re able to perform operations that mix-and-match different types.

#include "stdio.h";

int main() {
    int a = 35;
    char b = '6';

    /* Will output "89", because the character '6' is represented
       by the number 54 in memory */
    printf("%d", a + b);

    /* Will get "Y", because the number 89 in memory represents
       the character "Y" */
    printf("%c", a + b);
}

Back to posts