Static vs Dynamic Type

Understanding Typing in Programming Language

Typing involves specifying the data type of a variable or allowing the programming language to deduce it automatically.

typing refers to the classification and handling of data based on its type, which defines the kind of values that variables can hold and the operations that can be performed on those values.

In programming, Data Type is a Classification which tells us 1) what type of value a variable will hold and 2) which mathematical, relational and logical operations can be done on those values without getting an error.

When people mention "type" in the following contexts, they mean "data types

Type Checking: Type checking is the process of verifying and enforcing the constraints of types.

                    Typing Systems
             ______________|______________
            |                              |
     Static Typing                  Dynamic Typing
    ________|_________          _________|_________
   |                   |        |                   |
Strongly Typed    Weakly Typed  Strongly Typed   Weakly Typed
 (e.g., Haskell,   (e.g., C,    (e.g., Python,   (e.g., JavaScript,
   Rust)             C++)         TypeScript)       PHP)

In each programming language, to minimize the chance of getting an error, type checking is done either before or during program execution. Depending on the Timing of Type Checking, there are two types of programming languages: Statically Typed and Dynamically Typed languages (or mixed, where the user says which to use (static/dynamic) for each variable).

Also, depending on whether Implicit Type Conversion happens or not, there are two types of programming languages: Strongly Typed and Weakly Typed languages.

# Static Typing #

Does type checking at compile-time

In languages with static typing, variables are assigned a specific type at compile time, and type checking is performed before the code is executed. This means that the type of a variable is known and fixed throughout the program's execution. Languages like Java, C, and Haskell employ static typing systems.

Definition: The types of variables are explicitly declared and checked at compile time.

  • In source code, at the time of variable declaration (the time when a value is assigned to a new variable), the data type of that variable must be explicitly specified (i.e., cannot be implicit/inferred/guesses).
  • Here, data type is associated with the variable (the variable name, not the value).
  • If we try to change the data type of an already declared variable (int count) by assigning a value of a different data type (int count = “hello”) into it, then it will get an error.
  • If we try to change the data type by redeclaring an already declared variable (int count) using a different data type (boolean count) then we will also get an error.
int count;         /* count is int type, association between data type
                      and variable is static or fixed */

count = 10;        // no error 
count = 'Hello';   // error 
boolean count;     // error

Example:

int x = 10; // x is explicitly declared as an integer
String name = "John"; // name is explicitly declared as a string

In this example, the variables x and message are explicitly declared with their respective types (int and String). The compiler ensures that only operations compatible with these types are allowed, providing type safety and catching errors at compile time.

In this once we set a variable to a type, you cannot change it.

Example:

String str = "Hello";  // variable str statically typed as string
str = 5;               // would throw an error since str is
                       // supposed to be a string only

Characteristics:

  1. Early Error Detection: Type errors are caught at compile time, reducing the likelihood of runtime errors.
  2. Enhanced Readability: Explicit type declarations make code easier to understand and maintain.
  3. Improved Performance: Static typing allows for more efficient optimization by the compiler.

# Dynamic Typing #

Does type checking at run-time

In contrast, dynamic typing allows variables to hold values of any type, and type checking is performed at runtime rather than compile time. This provides flexibility and expressiveness but may increase the risk of runtime errors if types are mismatched. Languages like Python, JavaScript, and Ruby embrace dynamic typing.

Definition: In dynamically-typed languages, variables can hold values of any type, and type checking is performed at runtime.

  • No need to explicitly specify the data type of that variable. Because type checking is done during runtime, the language's system determines variable type from the data type of the assigned value of that variable.
  • Here, data type is associated with the value assigned to the variable. For example: var foo = 10 10 is a Number so now foo is of Number data type. But this association is dynamic (flexible).
  • We can easily change data type of an already declared variable (var foo = 10), by assigning a value of different data type (foo = “hi”) into it, not producing an error.
var foo;            // without assigned value, variable holds undefined data type 

var foo = 10;       // foo is Number type now, association between data 
                    // type and value is dynamic / flexible 
foo = 'Hi';         // foo is String type now, no error 
var foo = true;     // foo is Boolean type now, no error 

Example:

x = 10 # x can hold any value, its type is determined at runtime
name = "John" # name can also hold any value, its type is determined at runtime

Characteristics:

  1. Type checking is done at runtime.
  2. Type annotations are optional or implicit.
  3. Variables can change values dynamically during program execution.
  4. Offers flexibility and expressiveness but may lead to runtime errors if types are used incorrectly.

Within Static and Dynamic Typing, There is Strong and Weak Typing

## Strong Typing ##

Strong-typing enforce strict type rules and do not allow implicit type conversions that may result in loss of data or precision. Operations between incompatible types are typically prohibited.

  • The type of a variable is enforced more strictly. Operations between variables of different types are often require explicit type conversion.  This help catch type-related errors at compile time, leading to more predictable and reliable code.

Example:

// TypeScript example (strongly typed)
let x: number = 5; // x is explicitly declared as a number
let y: string = "Hello, TypeScript!"; // y is explicitly declared as a string

// TypeScript compiler ensures type safety
let result: number = x + y; // Error: Operator '+' cannot be applied to types 'number' and 'string'

In this TypeScript example, the variable x is declared as a number, and y is declared as a string. When we try to perform an addition operation between x (a number) and y (a string), the TypeScript compiler detects the type mismatch and produces a compilation error, preventing the code from being executed.

Characteristics:

  1. Prohibits implicit type conversions and ensures type safety (Type safety is priority).
  2. Operations between incompatible types are not allowed.
  3. Helps maintain data integrity and prevents unintended behaviors.

## Weak Typing ##

Definition: Weakly-typed languages allow implicit type conversions and may perform them automatically to accommodate different data types in operations.

  • It is more permissive with type conversions and allow implicit type conversion in many cases. This flexibility can lead to unexpected behavior and make it easier to introduce bugs related to type mismatches.

Here's an example in a weakly-typed language like JavaScript:

// JavaScript example (weakly typed)
let x = 5; // x is not explicitly typed
let y = "Hello, JavaScript!"; // y is not explicitly typed

// JavaScript performs implicit type conversion
let result = x + y; // result will be "5Hello, JavaScript!"

In this JavaScript example, the variables x and y are not explicitly declared with types. JavaScript implicitly assigns types to variables based on the values they hold (x gets a number type, and y gets a string type). When we perform an addition operation between x and y, JavaScript implicitly converts the number x to a string and concatenates it with the string y, resulting in "5Hello, JavaScript!".

Characteristics:

  1. Allows implicit type conversions, which can lead to unexpected results.
  2. Offers flexibility but may result in data loss or subtle bugs.
  3. Operations between different types are permitted, and conversions are often performed automatically.

Difference

 Statically Typed Strong TypingStatically Typed Weak TypingDynamically Typed Strong TypingDynamically Typed Weak Typing
Type CheckingCompile TimeCompile TimeRuntimeRuntime
Type AnnotationsRequiredRequiredOptionalOptional
Type EnforcementStrictLess strictStrictLess strict
Type ConversionsExplicitExplicit or implicitExplicitExplicit or implicit
Type InferenceLimitedLimitedCommonCommon
ExamplesHaskell, RustC, C++Python, TypeScriptJavaScript, PHP