Skip to content

Instantly share code, notes, and snippets.

@MangaD
Created August 11, 2026 09:53
Show Gist options
  • Select an option

  • Save MangaD/035f02ff86e9d01b748cb064372b93c8 to your computer and use it in GitHub Desktop.

Select an option

Save MangaD/035f02ff86e9d01b748cb064372b93c8 to your computer and use it in GitHub Desktop.
A Comprehensive Taxonomy of Programming Language Concepts, Features, and Tooling

A Comprehensive Taxonomy of Programming Language Concepts, Features, and Tooling

CC0

Disclaimer: ChatGPT generated document.

Programming languages can look very different on the surface, but underneath they are built from many of the same recurring concepts. C++ has templates and RAII, Java has interfaces and garbage collection, Rust has traits and ownership, Haskell has algebraic data types and type classes, Python has dynamic typing and comprehensions, and JavaScript has prototypes and promises. These features differ in syntax and implementation, but they often solve the same fundamental problems: how to represent data, organize code, control execution, manage memory, express abstraction, handle errors, and coordinate concurrent work.

This taxonomy is intended as a broad, language-independent map of that territory. It distinguishes the core language from the standard library, runtime, compiler or interpreter, toolchain, ecosystem, programming paradigms, and the deeper concepts from programming-language theory that explain how these systems work. Within each area, it groups related constructs and mechanisms—such as functions, pattern matching, generics, closures, modules, ownership, garbage collection, async/await, macros, type inference, and many others—so that unfamiliar terminology can be placed into a larger conceptual structure.

The goal is not merely to list features found in particular languages, but to provide a reusable mental model for understanding almost any programming language. When encountering a new concept, you should be able to ask: What category does this belong to? What problem does it solve? At what layer does it operate? And what alternative approaches do other languages use?

No taxonomy can literally contain every idea ever explored in programming-language research, and some concepts naturally overlap several categories. Nevertheless, the following provides a comprehensive map of the major concepts, constructs, mechanisms, abstractions, tools, and theoretical foundations encountered across modern and historical programming languages.

A taxonomy of programming languages

At the highest level:

Programming Language / Programming Platform
│
├── A. Core Language
│   ├── Lexical structure
│   ├── Syntax & grammar
│   ├── Names & binding
│   ├── Values & data
│   ├── Type system
│   ├── Expressions
│   ├── Statements
│   ├── Control flow
│   ├── Pattern matching
│   ├── Functions
│   ├── Abstraction
│   ├── Object-oriented features
│   ├── Generic programming
│   ├── Functional programming
│   ├── Modules
│   ├── Metaprogramming
│   ├── Error handling
│   ├── Resource/lifetime management
│   ├── Concurrency
│   └── Low-level/system features
│
├── B. Standard Library / Standard API
│
├── C. Runtime & Execution Model
│
├── D. Language Implementation
│
├── E. Build & Toolchain
│
├── F. Package & Dependency Ecosystem
│
├── G. Development Tools
│
├── H. Programming Paradigms
│
└── I. Language Design / PL Theory

The distinction between these levels matters. Pattern matching, for example, is primarily a core-language control/data-decomposition feature. A hash map is usually a standard-library data structure. Garbage collection is primarily a runtime/memory-management mechanism. Maven is build/dependency tooling. Functional programming is a paradigm rather than one particular construct.

Now let's expand the tree.


A. Core language

1. Lexical structure

Before a language even has expressions, it has rules for turning source text into tokens.

Lexical Structure
├── Character set / source encoding
├── Whitespace
├── Significant whitespace
├── Line terminators
├── Comments
│   ├── Line comments
│   ├── Block comments
│   ├── Nested comments
│   └── Documentation comments
├── Identifiers
├── Keywords
│   ├── Reserved keywords
│   └── Contextual keywords
├── Literals
│   ├── Integer
│   ├── Floating-point
│   ├── Boolean
│   ├── Character
│   ├── String
│   ├── Raw string
│   ├── Byte string
│   ├── Regex
│   ├── Null/nil
│   └── Collection literals
├── Operators
├── Punctuation / delimiters
├── Escape sequences
└── Tokens / lexemes

For example:

x = 42

might lex approximately into:

IDENTIFIER("x")
EQUALS
INTEGER_LITERAL(42)

Related concepts include lexing, tokenization, and scanner.


2. Grammar and syntax

The grammar determines which combinations of tokens form valid programs.

Syntax
├── Grammar
├── Productions / grammar rules
├── Expressions
├── Statements
├── Declarations
├── Definitions
├── Blocks
├── Scope-forming constructs
├── Precedence
├── Associativity
├── Ambiguity
└── Syntactic sugar

Languages are commonly described formally using things such as:

BNF
EBNF
Context-free grammars
Parsing expression grammars

An important distinction is:

syntax = how something is written

semantics = what it means.


3. Names, identifiers and binding

A huge amount of language design concerns the relationship between names and things.

Names & Binding
├── Identifier
├── Declaration
├── Definition
├── Binding
├── Name resolution
├── Scope
│   ├── Lexical/static scope
│   └── Dynamic scope
├── Visibility
├── Shadowing
├── Hiding
├── Namespace
├── Qualified names
├── Aliases
├── Imports
├── Exports
├── Forward declarations
└── Linkage

For example:

int x = 10;

creates a binding roughly:

name x → object/value

4. Scope

Scope deserves its own subdivision.

Scope
├── Global scope
├── Module scope
├── Namespace scope
├── File scope
├── Class scope
├── Function scope
├── Block scope
├── Expression scope
├── Lexical scope
└── Dynamic scope

Related concepts:

visibility
accessibility
lifetime
storage duration
linkage

These are related but not identical.


5. Values and data

The next major area is the language's data model.

Values
├── Literal values
├── Variables
├── Constants
├── Mutable values
├── Immutable values
├── References
├── Objects
├── Identity
├── Equality
├── Copying
├── Moving
└── Aliasing

Important distinctions include:

value vs object
value vs reference
identity vs equality
mutable vs immutable
copy vs reference semantics

6. Primitive / fundamental data types

Typical primitive types include:

Primitive Types
├── Boolean
├── Integer
│   ├── Signed
│   ├── Unsigned
│   ├── Fixed width
│   ├── Arbitrary precision
│   └── Machine word
├── Floating point
├── Decimal
├── Fixed point
├── Character
├── Byte
├── String
├── Symbol
├── Unit
├── Void
├── Null / nil / none
└── Never / bottom

Not every language considers these "primitive." For example, whether strings are primitive, objects, or library types varies considerably.


7. Composite / aggregate types

Composite Types
├── Arrays
├── Tuples
├── Records
├── Structs
├── Classes
├── Objects
├── Enumerations
├── Tagged unions
├── Variant types
├── Discriminated unions
├── Algebraic data types
├── Product types
├── Sum types
├── Lists
├── Maps
├── Sets
└── User-defined types

This leads into an important theoretical distinction.

Product types

A value contains A and B:

Person = String × Int

roughly:

struct Person {
    name: String,
    age: u32
}

Sum types

A value is A or B:

Result = Success | Failure

Rust:

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Haskell:

data Either a b = Left a | Right b

These are algebraic data types (ADTs).


8. Type systems

This is one of the largest branches.

Type Systems
├── Static typing
├── Dynamic typing
├── Strong typing
├── Weak typing
├── Explicit typing
├── Implicit typing
├── Type inference
├── Structural typing
├── Nominal typing
├── Duck typing
├── Gradual typing
├── Dependent typing
├── Refinement typing
├── Linear typing
├── Affine typing
├── Ownership typing
├── Effect typing
├── Flow-sensitive typing
├── Path-sensitive typing
├── Occurrence typing
└── Optional typing

These dimensions are mostly independent.

For example:

C++        statically typed + mostly nominal
Java       statically typed + nominal
Python     dynamically typed + duck typing
TypeScript gradually typed + structural
Rust       statically typed + nominal + affine/ownership features
Haskell    statically typed + extensive inference

9. Type relationships

Type Relationships
├── Type equivalence
├── Type compatibility
├── Subtyping
├── Supertyping
├── Inheritance
├── Interface implementation
├── Structural compatibility
├── Coercion
├── Conversion
├── Casting
├── Upcasting
├── Downcasting
└── Type erasure

Subtyping itself introduces:

A <: B

meaning approximately:

A can be used where B is expected.


10. Polymorphism

A particularly important taxonomy:

Polymorphism
├── Ad-hoc polymorphism
│   ├── Function overloading
│   └── Operator overloading
│
├── Parametric polymorphism
│   ├── Generics
│   └── Templates
│
├── Subtype polymorphism
│   ├── Interfaces
│   ├── Virtual methods
│   └── Dynamic dispatch
│
└── Coercion polymorphism

This is why "polymorphism" does not merely mean OOP.

C++ templates and Java generics are examples of parametric polymorphism, while overriding virtual/interface methods gives subtype polymorphism.


11. Generic programming

Generic Programming
├── Type parameters
├── Generic functions
├── Generic types
├── Generic classes
├── Templates
├── Constraints
├── Bounds
├── Concepts
├── Traits
├── Type classes
├── Associated types
├── Higher-kinded types
├── Variance
│   ├── Covariance
│   ├── Contravariance
│   └── Invariance
├── Monomorphization
├── Type erasure
└── Reification

Different languages attack the same problem differently:

C++        templates + concepts
Java       generics + bounds
Rust       generics + traits
Haskell    type variables + type classes
C#         generics + constraints
Swift      generics + protocols

12. Expressions

An expression generally computes or produces a value.

Expressions
├── Literals
├── Variable references
├── Arithmetic
├── Comparison
├── Logical operations
├── Bitwise operations
├── Assignment expressions
├── Conditional expressions
├── Function calls
├── Method calls
├── Member access
├── Indexing
├── Slicing
├── Casts
├── Object construction
├── Lambda expressions
├── Comprehensions
├── Await expressions
├── Match expressions
└── Block expressions

Some languages are heavily expression-oriented.

Rust:

let x = if condition {
    10
} else {
    20
};

Here if produces a value.


13. Operators

Operators
├── Arithmetic
│   ├── +
│   ├── -
│   ├── *
│   ├── /
│   └── %
├── Comparison
├── Equality
├── Logical
├── Bitwise
├── Shift
├── Assignment
├── Compound assignment
├── Increment/decrement
├── Address/dereference
├── Member access
├── Indexing
├── Function application
├── Null-coalescing
├── Optional chaining
├── Pipeline
├── Range
└── User-defined operators

Concepts include:

arity
unary
binary
ternary
precedence
associativity
short-circuiting
operator overloading

14. Statements

Statements generally perform actions rather than produce values.

Statements
├── Expression statement
├── Declaration statement
├── Assignment
├── Block
├── Conditional
├── Loop
├── Jump
├── Return
├── Throw
├── Yield
├── Assert
├── Import
└── Empty statement

Some languages blur or eliminate the expression/statement distinction.


15. Control flow

This is another major family.

Control Flow
├── Sequence
├── Selection
│   ├── if
│   ├── if/else
│   ├── switch
│   ├── case
│   ├── match
│   └── conditional expression
│
├── Iteration
│   ├── while
│   ├── do-while
│   ├── for
│   ├── foreach
│   └── loop
│
├── Jumps
│   ├── break
│   ├── continue
│   ├── return
│   └── goto
│
├── Exceptions
├── Coroutines
├── Generators
├── Continuations
└── Recursion

16. Pattern matching

The example you specifically mentioned belongs to a surprisingly large family.

A pattern describes the shape a value must have and often simultaneously introduces bindings.

Basic example:

match value {
    Some(x) => println!("{x}"),
    None => println!("nothing"),
}

Taxonomy:

Pattern Matching
├── Literal patterns
├── Variable/binding patterns
├── Wildcard patterns
├── Constant patterns
├── Tuple patterns
├── Record/struct patterns
├── Constructor patterns
├── Variant patterns
├── List patterns
├── Array patterns
├── Range patterns
├── Type patterns
├── Or-patterns
├── And-patterns
├── Nested patterns
├── Rest/spread patterns
├── Alias/as-patterns
├── Guarded patterns
└── Regex/string patterns

Pattern matching is closely connected to destructuring.

JavaScript:

const {name, age} = person;

Python:

match value:
    case ("point", x, y):
        ...

Haskell:

head (x:xs) = x

Rust, Scala, OCaml, F#, Erlang, Elixir, Haskell and increasingly Python/Java/C# all expose different forms of this idea.


17. Destructuring

Related but separable from matching:

Destructuring
├── Tuple destructuring
├── Array destructuring
├── Object/record destructuring
├── Nested destructuring
└── Rest destructuring

Example:

const [first, second] = values;

This essentially means:

decompose this structured value and bind its components to names.


18. Functions

A gigantic category in its own right.

Functions
├── Declaration
├── Definition
├── Parameters
├── Arguments
├── Return values
├── Multiple return values
├── Default parameters
├── Named parameters
├── Optional parameters
├── Variadic parameters
├── Function overloading
├── Anonymous functions
├── Lambdas
├── Closures
├── Nested functions
├── Local functions
├── Higher-order functions
├── First-class functions
├── Pure functions
├── Recursive functions
├── Tail recursion
├── Generic functions
├── Methods
├── Extension methods
├── Coroutines
├── Generators
└── Async functions

Important terminology:

first-class function means functions can themselves be treated as values.

higher-order function means a function takes functions as arguments and/or returns them.


19. Closures

A closure is approximately:

function + captured environment

For example:

function makeAdder(x) {
    return y => x + y;
}

The returned function retains access to x.

Related concepts:

free variables
captured variables
capture by value
capture by reference
lexical environment
closure object
escaping closure
non-escaping closure

20. Functional-programming constructs

Functional Features
├── First-class functions
├── Higher-order functions
├── Lambdas
├── Closures
├── Immutability
├── Pure functions
├── Function composition
├── Currying
├── Partial application
├── Recursion
├── Tail recursion
├── Pattern matching
├── Algebraic data types
├── Persistent data structures
├── Lazy evaluation
├── Referential transparency
├── Functors
├── Applicatives
├── Monads
└── Algebraic effects

Some of these are mathematical abstractions rather than literal keywords.


21. Object-oriented constructs

Object-Oriented Features
├── Objects
├── Classes
├── Instances
├── Fields
├── Properties
├── Methods
├── Constructors
├── Destructors
├── Encapsulation
├── Information hiding
├── Access modifiers
├── Inheritance
├── Multiple inheritance
├── Abstract classes
├── Interfaces
├── Protocols
├── Traits
├── Mixins
├── Composition
├── Delegation
├── Method overriding
├── Method overloading
├── Virtual methods
├── Dynamic dispatch
├── Static dispatch
├── Message passing
├── Reflection
└── Metaclasses

And an important conceptual hierarchy:

Polymorphism
        │
        ├── Subtype polymorphism
        │       └── dynamic dispatch
        │
        ├── Parametric polymorphism
        │       └── generics
        │
        └── Ad-hoc polymorphism
                └── overloading

22. Encapsulation and access control

Access Control
├── public
├── private
├── protected
├── internal/package
├── friend
├── module-private
├── file-private
└── capability-based access

Related concepts:

encapsulation
information hiding
API boundary
implementation detail
interface
contract

23. Modules and program organization

At larger scales:

Program Organization
├── Source file
├── Translation unit
├── Module
├── Package
├── Namespace
├── Crate
├── Assembly
├── Library
├── Component
├── Import
├── Export
├── Include
├── Re-export
├── Visibility
├── Module interface
└── Dependency

Names vary substantially:

C++       namespaces, translation units, modules
Java      packages, modules
Python    modules, packages
Rust      modules, crates
C#        namespaces, assemblies
JavaScript modules, packages
Go        packages, modules

24. Error handling

Error Handling
├── Return codes
├── Sentinel values
├── Null/nil
├── Exceptions
│   ├── throw
│   ├── try
│   ├── catch
│   ├── finally
│   ├── checked exceptions
│   └── unchecked exceptions
├── Result types
├── Option/Maybe types
├── Error unions
├── Panic
├── Assertions
├── Preconditions
├── Postconditions
└── Contracts

Three major philosophies are roughly:

C/Go style       explicit error values
Java/C# style    exceptions
Rust style       algebraic Result/Option values

Languages can combine these.


25. Nullability and optionality

A whole subfield:

Absence
├── Null
├── Nil
├── None
├── Optional
├── Maybe
├── Nullable types
├── Non-null types
├── Null-coalescing
├── Optional chaining
└── Null safety

For example:

T

versus

Optional<T>

makes absence explicit in the type system.


26. Memory model

Now we get closer to systems programming.

Memory
├── Stack
├── Heap
├── Static storage
├── Thread-local storage
├── Automatic storage
├── Dynamic allocation
├── Object lifetime
├── Storage duration
├── Alignment
├── Padding
├── Object representation
├── Memory layout
└── Memory ordering

27. Memory-management strategies

Memory Management
├── Manual allocation
│   ├── malloc/free
│   └── new/delete
│
├── Garbage collection
│   ├── Reference counting
│   ├── Tracing GC
│   ├── Mark-and-sweep
│   ├── Mark-and-compact
│   ├── Copying GC
│   ├── Generational GC
│   └── Concurrent GC
│
├── Automatic reference counting
├── Ownership
├── Borrowing
├── Regions
├── Arenas
└── RAII

Languages occupy different points:

C          manual
C++        RAII + manual + smart pointers
Java       tracing GC
Python     reference counting + cyclic GC
Rust       ownership/borrowing + RAII
Swift      ARC
Go         GC

28. References and pointers

Indirection
├── References
├── Raw pointers
├── Smart pointers
│   ├── Unique ownership
│   ├── Shared ownership
│   └── Weak references
├── Borrowed references
├── Interior pointers
├── Function pointers
├── Null pointers
├── Fat pointers
└── Handles

Operations/concepts:

address-of
dereferencing
pointer arithmetic
aliasing
provenance
nullability
dangling pointers
use-after-free

29. Ownership and borrowing

Rust makes these especially visible, but the concepts are broader.

Ownership
├── Owner
├── Move semantics
├── Copy semantics
├── Borrowing
│   ├── Shared borrow
│   └── Mutable borrow
├── Lifetimes
├── Lifetime parameters
├── Borrow checking
├── Aliasing rules
├── Interior mutability
└── RAII

30. Resource management

Memory isn't the only resource.

Resources
├── Memory
├── Files
├── Sockets
├── Locks
├── Database connections
├── OS handles
├── GPU resources
└── Transactions

Mechanisms include:

RAII
try/finally
defer
using
with/context managers
destructors
finalizers
scope guards

For example Python's:

with open(...) as f:
    ...

is a context-management/resource-management construct.


31. Iteration

Iteration
├── Index-based iteration
├── Iterator
├── Iterable
├── Enumerator
├── Generator
├── Range
├── Stream
├── Lazy sequence
├── Comprehension
└── Iterator protocol

This gives us distinctions such as:

collection
iterable
iterator
generator
stream

which aren't synonymous.


32. Comprehensions

Examples:

[x * x for x in numbers if x > 0]

Taxonomy:

Comprehensions
├── List comprehension
├── Set comprehension
├── Dictionary comprehension
├── Generator expression
└── Query comprehension

They combine:

iteration
mapping
filtering
construction

into one construct.


33. Lazy vs eager evaluation

Evaluation Strategy
├── Eager / strict
├── Lazy
├── Call-by-value
├── Call-by-reference
├── Call-by-name
├── Call-by-need
├── Normal-order
└── Applicative-order

Haskell is famously lazy by default.

Most mainstream imperative languages are predominantly eager.


34. Parameter-passing semantics

Parameter Passing
├── Pass by value
├── Pass by reference
├── Pass by sharing
├── Pass by name
├── Pass by need
├── Copy-in/copy-out
└── Move

This is frequently confused in discussions of languages like Python and Java.


35. Mutability

Mutability
├── Mutable binding
├── Immutable binding
├── Mutable object
├── Immutable object
├── const
├── readonly
├── final
├── persistent structures
└── interior mutability

Crucially:

immutable variable

and

immutable object

are not necessarily the same thing.


36. Concurrency

Another enormous branch:

Concurrency
├── Threads
├── Processes
├── Tasks
├── Fibers
├── Coroutines
├── Green threads
├── Actors
├── Goroutines
├── Async/await
├── Futures
├── Promises
├── Channels
├── Message passing
├── Shared memory
├── Structured concurrency
└── Reactive programming

37. Synchronization

Synchronization
├── Mutex
├── Recursive mutex
├── Read/write lock
├── Spinlock
├── Semaphore
├── Monitor
├── Condition variable
├── Barrier
├── Latch
├── Atomic operation
├── Compare-and-swap
├── Memory fence
├── Transaction
└── Lock-free algorithms

Associated concepts:

race condition
data race
deadlock
livelock
starvation
fairness
atomicity
visibility
ordering
happens-before

38. Parallelism

Concurrency and parallelism aren't identical.

Parallelism
├── Data parallelism
├── Task parallelism
├── SIMD
├── Vectorization
├── Multithreading
├── Multiprocessing
├── GPU computing
└── Distributed computing

A useful distinction:

Concurrency concerns multiple computations making progress.

Parallelism concerns computations executing simultaneously.


39. Asynchronous programming

Async Programming
├── Callbacks
├── Event loops
├── Futures
├── Promises
├── async/await
├── Coroutines
├── Async generators
├── Reactive streams
├── Completion handlers
└── Continuations

JavaScript, C#, Python, Rust, Kotlin and many others expose variants of this model.


40. Coroutines and generators

Coroutines
├── Stackful coroutines
├── Stackless coroutines
├── Symmetric coroutines
├── Asymmetric coroutines
├── Generators
├── Async coroutines
└── Resumable functions

Core operations include:

yield
resume
suspend
await

41. Continuations

A more advanced control-flow concept:

Continuation
├── Continuation-passing style
├── First-class continuation
├── Delimited continuation
├── call/cc
└── Continuation transformation

A continuation roughly represents:

"the rest of the computation."

This is an important concept behind exceptions, coroutines, async transformations and some functional-language features.


42. Metaprogramming

Programs that manipulate or generate programs:

Metaprogramming
├── Preprocessor
├── Macros
│   ├── Textual macros
│   ├── Syntactic macros
│   ├── Hygienic macros
│   ├── Procedural macros
│   └── Attribute macros
├── Templates
├── Compile-time evaluation
├── constexpr
├── Reflection
├── Introspection
├── Code generation
├── AST transformation
├── Annotation processing
├── Compiler plugins
└── Staged programming

Different examples:

C          preprocessor macros
C++        templates + constexpr
Rust       declarative/procedural macros
Lisp       macros
Java       reflection + annotation processors
C#         reflection + source generators

43. Reflection and introspection

Runtime Introspection
├── Inspect type
├── Inspect members
├── Inspect annotations
├── Discover methods
├── Dynamic invocation
├── Construct objects dynamically
├── Modify accessibility
└── Dynamic proxying

Related distinction:

introspection = inspect program structure

reflection = often inspect and manipulate/interact with program structure

though terminology varies.


44. Compile-time programming

Compile-Time Programming
├── Constant expressions
├── Constant evaluation
├── Templates
├── Compile-time functions
├── Type-level programming
├── Type computation
├── Macros
├── Code generation
└── Static assertions

This becomes especially sophisticated in:

C++
Rust
Haskell
Scala
D
Zig

45. Type-level programming

Here types themselves become computational objects.

Type-Level Programming
├── Type functions
├── Type families
├── Conditional types
├── Mapped types
├── Type traits
├── Template metaprogramming
├── Higher-kinded types
├── Phantom types
├── GADTs
├── Dependent types
└── Kind polymorphism

TypeScript, surprisingly, has an extremely expressive type-level language.


46. Algebraic effects and effect systems

A more advanced modern area:

Effects
├── Exceptions
├── State
├── I/O
├── Nondeterminism
├── Async
├── Logging
└── User-defined effects

An effect system tracks effects in the type system.

Related concepts:

effect handlers
algebraic effects
monadic effects
capability systems

Languages/research ecosystems such as Koka, Eff and newer language designs explore this heavily.


47. Low-level/system constructs

Systems languages expose things higher-level languages often hide.

Systems Features
├── Raw memory
├── Pointers
├── Pointer arithmetic
├── Memory layout
├── Alignment
├── Endianness
├── Bit manipulation
├── Volatile access
├── Atomics
├── Inline assembly
├── Intrinsics
├── SIMD
├── Foreign function interface
├── ABI control
├── Calling conventions
├── Linkage
├── Unsafe blocks
└── Zero-cost abstractions

48. Foreign-function interfaces

Languages need to communicate with other languages.

FFI
├── Native calls
├── C ABI
├── Calling conventions
├── Name mangling
├── Data marshalling
├── Struct layout
├── Dynamic libraries
├── Static libraries
├── Bindings
└── Interop layers

Examples:

Python ↔ C
Java ↔ JNI
C# ↔ P/Invoke
Rust ↔ C ABI

B. Standard library / standard API

Now we leave the language proper.

A typical standard library contains:

Standard Library
├── Core utilities
├── Data structures
├── Algorithms
├── Strings/text
├── Numeric facilities
├── I/O
├── Files
├── Networking
├── Dates/times
├── Concurrency
├── Randomness
├── Serialization
├── Regular expressions
├── Reflection
├── Process management
└── OS interfaces

Let's expand some.


49. Collections and data structures

Collections
├── Array
├── Dynamic array
├── Vector
├── List
├── Linked list
├── Stack
├── Queue
├── Deque
├── Set
├── Multiset
├── Map
├── Multimap
├── Dictionary
├── Hash table
├── Tree
├── Heap
├── Priority queue
├── Graph
├── Trie
├── Bitset
├── Bloom filter
└── Persistent collections

Not all of these are standard-library facilities in every language.


50. Algorithms

Algorithms
├── Searching
├── Sorting
├── Partitioning
├── Selection
├── Transformation
├── Filtering
├── Mapping
├── Folding/reduction
├── Accumulation
├── Comparison
├── Set operations
├── Heap operations
├── Numeric algorithms
└── Parallel algorithms

Functional vocabulary is especially useful:

map
filter
reduce/fold
scan
zip
flatMap/bind

51. Text processing

Text
├── Strings
├── Unicode
├── Encodings
├── Code points
├── Grapheme clusters
├── Formatting
├── Parsing
├── Regular expressions
├── Tokenization
├── Localization
└── Internationalization

52. I/O

I/O
├── Standard input
├── Standard output
├── Standard error
├── Streams
├── Buffered I/O
├── Binary I/O
├── Text I/O
├── Files
├── Memory-mapped files
├── Pipes
├── Sockets
└── Async I/O

53. Serialization

Serialization
├── Binary serialization
├── Text serialization
├── JSON
├── XML
├── CSV
├── Object serialization
├── Schema-based serialization
└── Encoding/decoding

54. Networking

Networking
├── TCP
├── UDP
├── Sockets
├── DNS
├── HTTP
├── TLS
├── URLs/URIs
├── WebSockets
└── Async networking

Whether these belong in the standard library varies considerably.


55. Numeric computing

Numerics
├── Integers
├── Floating point
├── Decimal
├── Big integers
├── Complex numbers
├── Rational numbers
├── Math functions
├── Statistics
├── Random numbers
├── Linear algebra
└── SIMD

C. Runtime and execution model

Now we're below the source-language surface.

56. Execution strategies

Execution
├── Interpretation
├── Ahead-of-time compilation
├── Just-in-time compilation
├── Bytecode interpretation
├── Native compilation
├── Transpilation
├── Hybrid execution
└── Partial evaluation

Examples:

C++          usually AOT → native
Java         source → bytecode → JVM/JIT
C#           source → IL → CLR/JIT/AOT
Python       source → bytecode → interpreter
JavaScript   parsing + interpretation/JIT
Rust         AOT → native
TypeScript   transpiles → JavaScript

57. Runtime system

Runtime
├── Program startup
├── Memory allocation
├── Garbage collection
├── Stack management
├── Exception handling
├── Thread management
├── Dynamic dispatch
├── Type information
├── Reflection
├── Dynamic loading
├── JIT compilation
└── Shutdown

58. Virtual machines

VM
├── Stack machine
├── Register machine
├── Bytecode
├── Bytecode verifier
├── Interpreter
├── JIT compiler
├── Garbage collector
├── Class/module loader
└── Runtime services

Examples include:

JVM
CLR
BEAM
WebAssembly runtimes
Lua VM
Python VM

59. ABI

Below APIs lies another crucial term:

ABI = Application Binary Interface

ABI
├── Calling convention
├── Register usage
├── Stack layout
├── Object layout
├── Symbol naming
├── Name mangling
├── Exception ABI
├── Binary formats
└── Linking conventions

API describes interaction at the source/programming level.

ABI describes compatibility at the binary level.


D. Compiler / interpreter architecture

A compiler itself has a taxonomy.

Source Code
    ↓
Lexer
    ↓
Tokens
    ↓
Parser
    ↓
AST
    ↓
Semantic Analysis
    ↓
Typed IR
    ↓
Optimization
    ↓
Code Generation
    ↓
Object Code
    ↓
Linker
    ↓
Executable

60. Compiler frontend

Frontend
├── Lexing
├── Parsing
├── AST construction
├── Name resolution
├── Scope analysis
├── Type checking
├── Type inference
├── Overload resolution
├── Generic instantiation
├── Borrow/lifetime checking
└── Semantic analysis

61. Intermediate representations

IR
├── AST
├── High-level IR
├── SSA
├── Control-flow graph
├── Data-flow graph
├── Bytecode
├── Machine-independent IR
└── Machine IR

SSA means Static Single Assignment form and is extremely important in modern compilers.


62. Compiler optimization

Optimization
├── Constant folding
├── Constant propagation
├── Dead-code elimination
├── Common-subexpression elimination
├── Copy propagation
├── Inlining
├── Loop unrolling
├── Loop invariant code motion
├── Strength reduction
├── Tail-call optimization
├── Escape analysis
├── Devirtualization
├── Vectorization
├── Instruction scheduling
├── Register allocation
└── Link-time optimization

63. Code generation

Backend
├── Instruction selection
├── Register allocation
├── Instruction scheduling
├── Machine-code emission
├── Object-file generation
├── Debug information
└── Relocations

64. Linking and loading

Linking
├── Object files
├── Symbols
├── Symbol tables
├── Static linking
├── Dynamic linking
├── Shared libraries
├── Relocations
├── Symbol resolution
├── Name mangling
└── Link-time optimization

Then:

Loader
├── Map executable
├── Map libraries
├── Resolve dynamic symbols
├── Initialize runtime
└── Transfer control

E. Build and toolchain

A complete development environment extends much further.

Toolchain
├── Compiler
├── Interpreter
├── Assembler
├── Linker
├── Loader
├── Build system
├── Package manager
├── Dependency resolver
├── Debugger
├── Profiler
├── Formatter
├── Linter
├── Static analyzer
├── Documentation generator
├── Test runner
├── Benchmark runner
├── REPL
└── Language server

65. Build systems

Build
├── Compilation units
├── Dependencies
├── Build graph
├── Incremental builds
├── Build caching
├── Configuration
├── Targets
├── Artifacts
├── Code generation
└── Cross-compilation

Examples:

C/C++       Make, CMake, Ninja, Meson, Bazel
Java        Maven, Gradle
Rust        Cargo
JavaScript  npm ecosystem tooling
C#          MSBuild/dotnet
Go          go tooling

66. Package management

Package Management
├── Package
├── Package registry
├── Manifest
├── Dependencies
├── Transitive dependencies
├── Version constraints
├── Dependency resolution
├── Lockfile
├── Semantic versioning
├── Feature flags
├── Workspace
├── Publishing
└── Vendoring

Examples:

npm
Cargo
pip
Maven
NuGet
RubyGems
Composer
Go modules

67. Static analysis

Static Analysis
├── Type checking
├── Linting
├── Data-flow analysis
├── Control-flow analysis
├── Nullability analysis
├── Taint analysis
├── Escape analysis
├── Ownership analysis
├── Dead-code detection
├── Security analysis
└── Formal verification

"Static" means reasoning without executing the program in the ordinary way.


68. Dynamic analysis

Dynamic Analysis
├── Debugging
├── Profiling
├── Tracing
├── Coverage
├── Sanitizers
├── Memory checking
├── Race detection
├── Runtime assertions
└── Instrumentation

69. Debugging

Debugger
├── Breakpoints
├── Conditional breakpoints
├── Watchpoints
├── Stepping
├── Stack traces
├── Call stacks
├── Variable inspection
├── Memory inspection
├── Registers
├── Core dumps
└── Remote debugging

70. Profiling and performance

Performance
├── CPU profiling
├── Memory profiling
├── Allocation profiling
├── Sampling
├── Instrumentation
├── Flame graphs
├── Tracing
├── Benchmarking
├── Microbenchmarking
└── Hardware performance counters

71. Testing

Testing isn't usually part of the language itself, but is a major programming-platform concept.

Testing
├── Unit testing
├── Integration testing
├── System testing
├── Acceptance testing
├── Regression testing
├── Property-based testing
├── Fuzz testing
├── Mutation testing
├── Snapshot testing
├── Golden testing
├── Differential testing
├── Stress testing
├── Load testing
└── Benchmarking

Supporting concepts:

assertion
fixture
mock
stub
fake
spy
test double
coverage

72. REPLs and interactive environments

REPL
= Read
→ Evaluate
→ Print
→ Loop

Common in:

Python
Lisp
Haskell
Julia
Ruby
JavaScript
Scala
Clojure

Closely related to notebooks and interactive shells.


73. Language servers

Modern editor support often follows the Language Server Protocol model.

Language Intelligence
├── Autocomplete
├── Go to definition
├── Find references
├── Rename
├── Diagnostics
├── Hover information
├── Signature help
├── Refactoring
└── Semantic highlighting

F. Programming paradigms

Features aren't the same thing as paradigms.

A paradigm is a broad model/style for expressing computation.

Programming Paradigms
├── Imperative
├── Procedural
├── Structured
├── Object-oriented
├── Functional
├── Declarative
├── Logic
├── Dataflow
├── Reactive
├── Event-driven
├── Concurrent
├── Actor-oriented
├── Array-oriented
├── Stack-oriented
├── Aspect-oriented
├── Generic
├── Metaprogramming
└── Constraint programming

Most modern languages are multi-paradigm.

C++ is simultaneously:

imperative
procedural
object-oriented
generic
functional-ish
metaprogramming-oriented
systems-oriented

74. Imperative programming

The program describes how state changes:

x = 1
x = x + 1

Core ideas:

state
mutation
assignment
sequence
loops
control flow

C, C++, Java, Python, etc. all support this.


75. Procedural programming

Imperative programming organized primarily around procedures/functions:

data
 ↓
procedure()
 ↓
procedure()
 ↓
result

C is the classic example.


76. Object-oriented programming

Organizes computation around interacting objects:

Object
├── state
└── behavior

Core concepts:

encapsulation
inheritance
polymorphism
dynamic dispatch
message passing
composition

But different OOP traditions emphasize different pieces. Smalltalk-style OOP and C++-style OOP aren't conceptually identical.


77. Functional programming

Organizes computation around function application and transformation of values.

input
 ↓
function
 ↓
value
 ↓
function
 ↓
output

Emphasizes:

immutability
pure functions
composition
higher-order functions
algebraic data types
pattern matching

78. Declarative programming

Instead of saying:

Do X, then Y, then Z.

you primarily describe:

I want a result satisfying these properties.

Examples include:

SQL
logic programming
constraint programming
regular expressions
build systems
configuration languages

79. Logic programming

Classic example: Prolog.

Concepts:

facts
rules
queries
unification
backtracking
resolution
relations

Instead of explicitly implementing an algorithm, you define logical relationships.


80. Reactive programming

Programs respond to changing values/events.

Reactive Programming
├── Event streams
├── Observables
├── Signals
├── Dataflow
├── Subscriptions
├── Backpressure
└── Propagation

81. Actor model

Concurrency based around isolated actors:

Actor
├── private state
├── mailbox
└── behavior
        ↑
     messages

Actors communicate via message passing rather than directly sharing memory.

Erlang/Elixir and Akka are prominent examples.


G. Programming-language theory

Now we reach concepts that explain why language features work.

82. Syntax vs semantics

Programming Language
├── Syntax
│   └── what programs look like
│
└── Semantics
    └── what programs mean

Semantics itself includes:

Operational semantics
Denotational semantics
Axiomatic semantics
Static semantics
Dynamic semantics

83. Static vs dynamic semantics

Static semantics covers properties established before execution:

type correctness
name resolution
scope rules
generic constraints

Dynamic semantics covers what happens during execution:

evaluation
function calls
mutation
exceptions
object creation

84. Type theory

The theoretical foundation becomes enormous:

Type Theory
├── Simply typed lambda calculus
├── Polymorphic lambda calculus
├── System F
├── Hindley-Milner
├── Subtyping
├── Algebraic data types
├── Recursive types
├── Existential types
├── Universal types
├── Dependent types
├── Linear types
├── Affine types
├── Refinement types
├── Intersection types
├── Union types
├── Effect systems
└── Kind systems

This is the theoretical backbone behind many modern language features.


85. Lambda calculus

A foundational model of computation.

A minimal lambda calculus essentially has:

variables
function abstraction
function application

For example:

λx.x

means roughly:

x => x

Many functional-programming concepts descend directly from lambda calculus.


86. Evaluation and reduction

Evaluation
├── Reduction
├── Normal form
├── Beta reduction
├── Alpha conversion
├── Substitution
├── Evaluation order
├── Normalization
└── Divergence

These become important when studying languages formally.


87. Computability

At an even deeper level:

Theory of Computation
├── Turing machines
├── Lambda calculus
├── Recursive functions
├── Turing completeness
├── Decidability
├── Undecidability
├── Halting problem
└── Computational complexity

Different formal models can describe equivalent classes of computation.


88. Formal methods

Formal Methods
├── Formal specification
├── Hoare logic
├── Preconditions
├── Postconditions
├── Invariants
├── Model checking
├── Theorem proving
├── Proof assistants
├── Refinement types
├── Dependent types
└── Program verification

Languages/tools such as Coq, Lean, Agda, Isabelle and Dafny live around this territory.


H. Some particularly important cross-language feature families

If your real objective is "I want to recognize the major ideas whenever I encounter a new language", I'd especially learn these families.

DATA
│
├── primitives
├── structs/records
├── tuples
├── arrays
├── collections
├── enums
├── sum types
└── product types

TYPES
│
├── static/dynamic
├── nominal/structural
├── inference
├── subtyping
├── generics
├── traits/interfaces
├── union/intersection types
├── nullability
└── dependent/refinement/linear types

CONTROL
│
├── conditionals
├── loops
├── recursion
├── pattern matching
├── exceptions
├── generators
├── coroutines
├── async/await
└── continuations

FUNCTIONS
│
├── functions
├── lambdas
├── closures
├── higher-order functions
├── currying
├── partial application
└── composition

ABSTRACTION
│
├── modules
├── namespaces
├── classes
├── interfaces
├── traits
├── protocols
├── generics
└── encapsulation

STATE & RESOURCES
│
├── mutation
├── references
├── pointers
├── ownership
├── borrowing
├── RAII
├── GC
└── immutability

CONCURRENCY
│
├── threads
├── locks
├── atomics
├── actors
├── channels
├── futures/promises
├── async/await
└── structured concurrency

METAPROGRAMMING
│
├── macros
├── reflection
├── templates
├── compile-time execution
├── code generation
└── type-level programming

Those are probably the highest-value branches of the tree.


I. A cross-language comparison

A comparison makes the taxonomy much easier to internalize:

Concept C++ Java Python Rust Haskell JavaScript
Static typing —*
Dynamic typing
Type inference limited runtime extensive runtime
OOP traits/structs limited prototype-based
Functions
First-class functions
Closures
Generics templates typing support parametric
Pattern matching limited/evolving evolving limited
ADTs variant/enums sealed types classes/unions enum manual
Exceptions panic only† exceptions/values
Result types library library-ish library/manual Either manual
GC
Ownership system
RAII limited context managers different model
Raw pointers unsafe
Traits/interfaces concepts interfaces protocols/duck traits type classes structural/duck
Macros preprocessor limited decorators/metaclasses extensions
Reflection RTTI/limited limited limited
Async coroutines libraries/runtime
Threads ✓‡ workers
Modules
Lazy evaluation library streams generators iterators default generators
Operator overloading mostly no traits type classes mostly no

* Python has optional/static type annotations and external/static checkers, but runtime Python remains dynamically typed.

† Rust deliberately uses Result for ordinary recoverable errors rather than exception-style propagation.

‡ Python's concurrency situation depends heavily on implementation and workload.

The table is necessarily approximate because languages often implement the same concept in radically different ways.


J. Another useful taxonomy: "What layer am I looking at?"

When you encounter an unfamiliar term, one of the best questions is:

At what layer does this thing exist?

Consider:

SOURCE LANGUAGE
    │
    ├── pattern matching
    ├── functions
    ├── classes
    ├── generics
    └── async/await
    │
    ▼
TYPE / STATIC SEMANTICS
    │
    ├── type inference
    ├── overload resolution
    ├── borrow checking
    └── effect checking
    │
    ▼
STANDARD LIBRARY
    │
    ├── strings
    ├── vectors
    ├── maps
    ├── algorithms
    └── filesystem
    │
    ▼
RUNTIME
    │
    ├── garbage collector
    ├── allocator
    ├── exception runtime
    ├── scheduler
    └── VM
    │
    ▼
COMPILER / INTERPRETER
    │
    ├── parser
    ├── optimizer
    ├── JIT
    └── code generator
    │
    ▼
ABI / MACHINE
    │
    ├── calling conventions
    ├── registers
    ├── stack
    ├── machine instructions
    └── memory
    │
    ▼
OPERATING SYSTEM
    │
    ├── processes
    ├── threads
    ├── virtual memory
    ├── files
    └── sockets
    │
    ▼
HARDWARE

This prevents a common learning problem: mixing concepts that live at completely different abstraction levels.

For example, for loop, iterator, thread, garbage collector, compiler, and CPU instruction are all relevant to executing a loop, but they are not the same kind of concept.


K. Language feature vs language mechanism vs library abstraction

There's another distinction worth learning.

Suppose you write:

for x in items:
    print(x)

There are several layers involved:

Syntax / construct: for

Language protocol/mechanism: iteration protocol

Library/data abstraction: list

Runtime: Python interpreter

OS: eventually handles terminal output

So we could classify terminology as:

Construct
    ↓
Language mechanism
    ↓
Abstraction / API
    ↓
Runtime mechanism
    ↓
Implementation mechanism

Similarly, Rust:

for x in collection {
    ...
}

involves the for language construct, iterator abstraction/protocol, Iterator trait, collection library type, compiler desugaring, and ultimately machine-level branching.

This distinction becomes extremely powerful once you're reading language specifications.


L. "Construct", "feature", "mechanism", "facility", "abstraction"

These words themselves have slightly different meanings.

Language construct

A syntactically recognizable building block:

if
for
while
function declaration
class declaration
match
lambda

Language feature

Broader term. Could include syntax or semantic capabilities:

generics
garbage collection
pattern matching
operator overloading
multiple inheritance

Mechanism

Describes how a capability is provided:

dynamic dispatch
reference counting
borrow checking
type erasure
monomorphization

Facility

Very general standards-language term:

language facility
library facility
concurrency facility

Abstraction

A conceptual interface that hides implementation details:

function
class
iterator
stream
future
collection

Idiom

A conventional way of combining features:

RAII
dependency injection
builder pattern
Python context managers

Paradigm

A broad programming worldview:

OOP
functional
procedural
logic
reactive

These distinctions will make technical literature considerably easier to read.


M. And above languages: software-engineering concepts

If by "everything" you mean the entire territory surrounding programming, the tree keeps expanding beyond language design:

Programming
│
├── Programming Languages
│
├── Algorithms
│   ├── searching
│   ├── sorting
│   ├── graph algorithms
│   ├── dynamic programming
│   └── computational geometry
│
├── Data Structures
│
├── Software Design
│   ├── abstraction
│   ├── modularity
│   ├── coupling
│   ├── cohesion
│   ├── SOLID
│   └── design patterns
│
├── Software Architecture
│   ├── layered
│   ├── hexagonal
│   ├── event-driven
│   ├── microservices
│   └── distributed systems
│
├── Operating Systems
│   ├── processes
│   ├── threads
│   ├── scheduling
│   ├── memory
│   └── filesystems
│
├── Computer Architecture
│   ├── CPU
│   ├── ISA
│   ├── caches
│   ├── memory
│   └── pipelines
│
├── Databases
│
├── Networks
│
├── Distributed Systems
│
├── Security
│
├── Compilers
│
├── Formal Methods
│
└── Theory of Computation

At that point we've moved from a taxonomy of programming languages toward a taxonomy of computer science/software engineering.


A compact master map

If I wanted one map on my wall while learning programming languages, I'd probably reduce everything above to this:

PROGRAMMING LANGUAGE
│
├── 1. SYNTAX
│   ├── tokens
│   ├── grammar
│   ├── expressions
│   ├── statements
│   └── declarations
│
├── 2. DATA MODEL
│   ├── values
│   ├── objects
│   ├── primitives
│   ├── aggregates
│   ├── references
│   ├── mutability
│   └── identity/equality
│
├── 3. TYPE SYSTEM
│   ├── static/dynamic
│   ├── nominal/structural
│   ├── inference
│   ├── subtyping
│   ├── polymorphism
│   ├── generics
│   ├── ADTs
│   ├── traits/interfaces
│   ├── variance
│   └── advanced types
│
├── 4. CONTROL FLOW
│   ├── conditionals
│   ├── loops
│   ├── pattern matching
│   ├── recursion
│   ├── exceptions
│   ├── generators
│   ├── coroutines
│   └── continuations
│
├── 5. FUNCTIONS
│   ├── parameters
│   ├── lambdas
│   ├── closures
│   ├── higher-order functions
│   ├── overloading
│   ├── currying
│   └── composition
│
├── 6. ABSTRACTION
│   ├── procedures
│   ├── classes
│   ├── interfaces
│   ├── traits
│   ├── generics
│   ├── modules
│   └── packages
│
├── 7. STATE & MEMORY
│   ├── assignment
│   ├── references
│   ├── pointers
│   ├── stack/heap
│   ├── allocation
│   ├── GC
│   ├── ownership
│   ├── borrowing
│   └── lifetimes
│
├── 8. ERRORS & EFFECTS
│   ├── exceptions
│   ├── Result
│   ├── Option
│   ├── panic
│   ├── contracts
│   └── effect systems
│
├── 9. CONCURRENCY
│   ├── processes
│   ├── threads
│   ├── tasks
│   ├── locks
│   ├── atomics
│   ├── channels
│   ├── actors
│   ├── futures
│   └── async/await
│
├── 10. METAPROGRAMMING
│   ├── macros
│   ├── templates
│   ├── reflection
│   ├── compile-time evaluation
│   ├── type-level programming
│   └── code generation
│
├── 11. MODULE SYSTEM
│   ├── modules
│   ├── packages
│   ├── namespaces
│   ├── imports
│   ├── exports
│   └── visibility
│
├── 12. STANDARD LIBRARY
│   ├── collections
│   ├── algorithms
│   ├── strings
│   ├── numerics
│   ├── I/O
│   ├── filesystem
│   ├── networking
│   ├── concurrency
│   └── utilities
│
├── 13. RUNTIME
│   ├── allocator
│   ├── GC
│   ├── VM
│   ├── JIT
│   ├── exceptions
│   ├── scheduler
│   └── dynamic loading
│
├── 14. IMPLEMENTATION
│   ├── lexer
│   ├── parser
│   ├── AST
│   ├── semantic analysis
│   ├── type checker
│   ├── IR
│   ├── optimizer
│   ├── code generator
│   ├── assembler
│   ├── linker
│   └── loader
│
├── 15. TOOLING
│   ├── build system
│   ├── package manager
│   ├── debugger
│   ├── profiler
│   ├── formatter
│   ├── linter
│   ├── static analyzer
│   ├── test framework
│   ├── REPL
│   ├── IDE
│   └── language server
│
├── 16. PARADIGMS
│   ├── imperative
│   ├── procedural
│   ├── object-oriented
│   ├── functional
│   ├── declarative
│   ├── logic
│   ├── reactive
│   ├── actor
│   └── concurrent
│
└── 17. THEORY
    ├── formal grammars
    ├── semantics
    ├── lambda calculus
    ├── type theory
    ├── computability
    ├── formal verification
    └── complexity

That's the mental model I'd recommend.

The particularly interesting realization is that C++, Java, Rust, Python, Haskell, JavaScript, etc. aren't collections of unrelated features. They are different sets of answers to essentially the same design questions:

What are values? How are values typed? How do we name them? How do we compose computations? How do we represent alternatives? How do we control execution? How do we abstract over types and behavior? How is state represented? Who owns memory/resources? How are errors represented? How do concurrent computations interact? What happens at compile time versus runtime? How are programs divided into components?

Once you start comparing languages along those axes, features such as C++ templates, Java generics, Rust traits, Haskell type classes, Python protocols, pattern matching, closures, coroutines, monads, ownership, etc. stop looking like an arbitrary vocabulary list. They become alternative solutions to recurring programming-language design problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment