Welcome to our collection of programming language explorations. From the ubiquitous to the almost-forgotten, every language here is still runnable on modern machines.

Each language guide progresses from Hello World through advanced topics, with Docker images provided for easy experimentation.

All source code is available in our Examples Repository on GitHub, auto-generated from this site’s tutorials.

View all 75+ languages we plan to cover →


Understanding Programming Languages

Programming languages differ in fundamental ways that affect how you think about and write code. Understanding these distinctions helps you choose the right tool for each task and appreciate how languages evolved.

Abstraction Level

Languages operate at different distances from the underlying hardware:

Low-level languages (Assembly, Machine Code) offer direct control over computer hardware and memory. They are fast and memory-efficient but difficult to read and write. Every CPU architecture requires different code.

High-level languages (Python, Java, JavaScript) abstract away hardware details using human-friendly syntax. They’re easier to learn and maintain, trading some performance for productivity and portability.

Mid-level languages (C, Rust) bridge the gap—providing hardware access when needed while offering higher-level constructs for everyday programming.

Programming Paradigm

How a language organizes and structures code:

FeatureImperativeProceduralObject-Oriented (OOP)Functional (FP)
Core ConceptExplicit step-by-step instructions that modify program stateSequence of procedure calls that operate on dataData and behavior bundled into objectsComputation as evaluation of pure functions
OrganizationStatements and control flowProcedures/functions and modulesObjects and classesFunctions and modules
State ManagementExplicit state changes via assignmentsState passed between procedures, often globalState encapsulated within objectsAvoided via immutable data and pure functions
Data HandlingVariables modified in placeData separate from procedures, often globalData encapsulated and hidden within objectsImmutable; functions produce new data
Key PrinciplesSequential execution, loops, conditionalsTop-down design, modularity via proceduresInheritance, polymorphism, encapsulationPure functions, immutability, first-class functions
Best Suited ForScripts, simple automation, direct hardware controlSystem programming, scripts, straightforward tasksLarge-scale applications, GUIs, complex systemsMath computations, data transformations, parallelism
ExamplesAssembly, early BASICC, Pascal, Fortran, COBOLJava, C++, C#, Python, RubyHaskell, Lisp, Erlang, Elixir, Scala

Declarative languages (SQL, HTML, CSS, Prolog) take a different approach entirely—you specify what you want, not how to achieve it. The language runtime figures out the steps.

Most modern languages are multi-paradigm, supporting several styles. Python supports procedural, object-oriented, and functional programming. Scala blends OOP with functional. Even C++ now has functional features.

Processing Method

How source code becomes executable:

Compiled languages (C, C++, Rust, Go) convert source code entirely into machine code before execution. A compiler analyzes the whole program, optimizes it, and produces a standalone executable. This results in fast execution but requires recompilation for each target platform.

Interpreted languages (Python, JavaScript, Ruby, PHP) execute code line-by-line at runtime through an interpreter. This enables rapid development and platform independence but typically runs slower than compiled code.

Hybrid approaches are common:

  • Bytecode compilation (Java, C#, Python) compiles to intermediate code that runs on a virtual machine. Java compiles to JVM bytecode; C# to CLR bytecode.
  • Just-In-Time (JIT) compilation dynamically compiles frequently-used code paths during execution, combining interpretation’s flexibility with near-native speeds.

Typing System

How languages handle data types:

Static vs. Dynamic typing:

AspectStatic TypingDynamic Typing
When checkedCompile timeRuntime
DeclarationTypes declared explicitly (usually)Types inferred from values
Error detectionCatches type errors before runningType errors appear at runtime
FlexibilityLess flexible, more predictableMore flexible, faster prototyping
PerformanceGenerally faster (compiler optimizations)Generally slower (runtime checks)
ExamplesJava, C, C++, Go, Rust, TypeScriptPython, JavaScript, Ruby, PHP

Strong vs. Weak typing:

Strongly typed languages (Java, Python, Rust) restrict operations between incompatible types. Adding a string to a number requires explicit conversion—the language won’t guess what you meant.

Weakly typed languages (C, PHP, JavaScript) perform implicit type conversions. JavaScript’s "5" + 3 gives "53" (string concatenation) while "5" - 3 gives 2 (numeric subtraction). This flexibility can lead to subtle bugs.

Type inference lets statically-typed languages feel more dynamic. Languages like Rust, Go, Kotlin, and TypeScript can often deduce types from context, giving you safety without verbose declarations.


Understanding these concepts helps you appreciate why certain languages excel at specific tasks—and why programmers often have strong opinions about their favorites.

Modern Languages

Languages from 2009 onwards, sorted newest first

Established Mainstream

Well-established languages widely used in enterprise and education, sorted by year

Classic & Historical

Languages with historical significance that shaped programming, sorted oldest first