
Case Sensitivity: A 70-Year Evolution from Fortran to Mojo
- March 16, 2026
- 8 min read
- Programming concepts
Table of Contents
I started my programming journey with Pascal.
In that world, MyVariable and myvariable were exactly the same thing.
The compiler didn’t care about capitalization.
Then I moved to C.
myVariable and MyVariable were now completely different identifiers: capitalization mattered.
Years later I picked up Go, and discovered that capitalization had gained an entirely new meaning. In Go, the case of the first letter controls visibility:
ExportedFunction()→ visible outside the packageinternalFunction()→ private to the package
At that point I started wondering:
Are programming languages becoming more case-sensitive over time?
To answer that question, I analyzed over 50 major languages created between 1957 and 2023 and mapped how each one treats capitalization.
The result is the chart below.
Before diving deeper, let’s clarify what case sensitivity means in programming.
A language is case-sensitive when identifiers that differ only by capitalization are treated as different symbols.
For example, print, Print, and PRINT would refer to three separate identifiers.
A case-insensitive language treats those variations as the same symbol.
The Great Divide: A Visual Analysis
Once languages are plotted chronologically, several patterns emerge.
The earliest languages were often case-insensitive, but that approach gradually disappeared. Modern languages overwhelmingly treat capitalization as meaningful.
At the same time, some languages began using capitalization not just for distinction, but to encode additional meaning in the language itself.
To understand the chart, it helps to look at the different models languages use.
Understanding the Different Case Sensitivity Models
Looking at the languages in the dataset, five distinct approaches to case sensitivity emerge. Some languages ignore capitalization entirely, while others treat it as meaningful syntax.
1. Fully Case-Insensitive Languages
In these languages, identifiers are compared without regard to capitalization.
Variable, variable, and VARIABLE all refer to the same symbol.
Examples: Fortran, COBOL, Pascal, Ada, Visual Basic, Delphi, PowerShell, Common Lisp
1with Ada.Text_IO; use Ada.Text_IO;
2procedure Example is
3 myVariable : String := "Hello World";
4begin
5 Put_Line (MYVARIABLE);
6end EXAMPLE;
This approach was common in early programming languages, where the goal was to reduce trivial errors. Historically, some computing systems and punch-card encodings didn’t even distinguish lowercase letters, so treating identifiers as case-insensitive simplified parsing.
Over time, however, this design became less common.
2. Strictly Case-Sensitive Languages
In case-sensitive languages, capitalization creates distinct identifiers.
1int value = 5;
2int Value = 10; // different variable
Examples include: C, C++, Python, JavaScript, Rust, Swift, Zig, Kotlin, TypeScript, Julia
This is now the dominant design choice in modern languages.
Case sensitivity provides:
- Clearer symbol boundaries
- More expressive naming
- Simpler compiler and tooling behavior
As software systems grew larger, these advantages became more important than avoiding capitalization typos.
3. Partial or Mixed Sensitivity
A few languages treat some identifiers as case-sensitive but others as case-insensitive.
The most famous example is PHP:
- Variables → case-sensitive
- Functions and classes → case-insensitive
1$user = "Alice";
2
3echo $USER; // Error (variables are sensitive)
4
5myFunction();
6MYFUNCTION(); // Works (functions are insensitive)
This hybrid model often reflects historical layering in language design.
4. Style-Insensitive Languages
A rare category ignores both case and certain formatting characters.
The main example is Nim.
In Nim, identifiers are normalized so that case and underscores do not matter.
1var my_variable = 10
2
3echo myVariable
4echo MYVARIABLE
All three identifiers resolve to the same symbol.
This design was introduced to make it easier to integrate libraries that use different naming conventions such as: camelCase, snake_case, PascalCase.
5. Case-Sensitive Languages with Semantic Meaning
Some languages go further: they are case-sensitive, but capitalization also conveys meaning inside the language.
In these languages, case is not just stylistic — it encodes part of the syntax.
Several distinct patterns appear in the dataset.
Variables vs. Atoms / Constants
Some languages use capitalization to distinguish variables from constant symbols.
Examples: Prolog, Erlang
1X = 10. % variable
2value = 10. % atom
Here, variables must start with an uppercase letter.
Types vs. Values
In many functional languages, capitalization distinguishes types from values or functions.
Examples: Haskell, Elm, OCaml, Gleam
1data Tree = Leaf Int | Node Tree Tree
Tree,Leaf,Node→ type and constructors- lowercase identifiers → functions or values
This convention makes it easier to visually separate data structures from runtime variables.
Constants vs. Variables
Some languages use capitalization to signal constants.
Examples: Ruby, Crystal
1MAX_SIZE = 100
A capitalized identifier denotes a constant rather than a mutable variable.
Visibility or Module Boundaries
In a few languages, capitalization controls public visibility.
Examples: Go
1func ExportedFunction() {} // public
2func privateFunction() {} // package-internal
Instead of using keywords like public or private, the language infers visibility from capitalization.
Naming Rules that Encode Structure
Some newer languages enforce capitalization patterns for different symbol categories.
Examples: V, C3
Typical rules may include:
PascalCase→ typesUPPER_CASE→ constantssnake_case→ variables (V)
This helps make code visually self-describing.
A Clear Historical Pattern
Looking across the dataset, a clear historical shift appears:
Early languages (1950s–1980s): Many were fully case-insensitive.
1990s onward: Case-sensitive languages became the dominant design.
Modern languages: Often remain case-sensitive but sometimes use capitalization to encode additional meaning.
In other words, the industry gradually moved from ignoring case to using it as a structural signal in the language itself.
Another pattern appears when separating native compiled languages from interpreted languages in the chart.
Native languages converge strongly toward strict case sensitivity.
After the 1990s, nearly every new native language in the dataset treats capitalization as significant.
Interpreted languages remain more diverse.
While many are case-sensitive (Python, JavaScript, Lua), others keep alternative models such as partial sensitivity (PHP), semantic casing (Ruby), or full case insensitivity (PowerShell).
This difference likely reflects their typical use cases: systems languages prioritize precision and unambiguous identifiers, while scripting environments historically favored convenience and flexibility.
Why Early Languages Ignored Case
The origins of case insensitivity are surprisingly practical.
Early computers often used limited character encodings. Many systems relied on 6-bit character sets or hardware that didn’t support lowercase letters at all.
Punch cards made this even more restrictive.
As a result, early languages like Fortran and COBOL simply treated uppercase and lowercase as identical.
Even after hardware improved, the convention stuck.
Languages such as Pascal and Ada intentionally preserved case insensitivity to avoid trivial syntax errors. The philosophy was simple:
The compiler should focus on meaning, not typography.
Pascal’s creator Niklaus Wirth designed the language primarily for teaching, so minimizing frustrating syntax mistakes was a deliberate goal.
So… Are Languages Becoming Case-Sensitive?
Looking at seventy years of language design, the answer is mostly yes. Modern languages overwhelmingly prefer strict case sensitivity. Why?
Because large software systems benefit from: unambiguous identifiers, consistent tooling, and clear namespace boundaries.
But the story isn’t entirely linear. Some languages experiment with semantic casing, while others (like Nim) attempt to reduce stylistic friction.
What started as a hardware limitation has evolved into a design choice — one that reflects the trade-offs each language makes between precision, readability, and developer ergonomics.
Newsletter
Subscribe to our newsletter and stay updated.
Detailed Language Table
| Language | Year | Execution Type | Sensitivity Classification |
|---|---|---|---|
| Fortran | 1957 | Native | Fully Insensitive |
| COBOL | 1959 | Native | Fully Insensitive |
| Pascal | 1970 | Native | Fully Insensitive |
| C | 1972 | Native | Sensitive |
| Prolog | 1972 | Interpreted | Sensitive + Semantic (Caps = Variables) |
| AWK | 1977 | Interpreted | Sensitive |
| Ada | 1983 | Native | Fully Insensitive |
| C++ | 1985 | Native | Sensitive |
| Objective-C | 1984 | Native | Sensitive |
| MATLAB | 1984 | Interpreted | Sensitive |
| Common Lisp | 1984 | Interpreted | Fully Insensitive |
| Erlang | 1986 | Interpreted | Sensitive + Semantic (Caps = Variables) |
| Perl | 1987 | Interpreted | Sensitive |
| Tcl | 1988 | Interpreted | Sensitive |
| Bash | 1989 | Interpreted | Sensitive |
| Haskell | 1990 | Native | Sensitive + Semantic (Caps = Types & Constructors) |
| Python | 1991 | Interpreted | Sensitive |
| Visual Basic | 1991 | Native | Fully Insensitive |
| R | 1993 | Interpreted | Sensitive |
| Lua | 1993 | Interpreted | Sensitive |
| Java | 1995 | Interpreted | Sensitive |
| PHP | 1995 | Interpreted | Partial (Sensitive Variables Only) |
| Ruby | 1995 | Interpreted | Sensitive + Semantic (Caps = Constants) |
| Racket | 1995 | Interpreted | Sensitive |
| Delphi | 1995 | Native | Fully Insensitive |
| JavaScript | 1995 | Interpreted | Sensitive |
| OCaml | 1996 | Native | Sensitive + Sensitive (Caps = Constructors & Mods) |
| C# | 2000 | Interpreted | Sensitive |
| D | 2001 | Native | Sensitive |
| Scala | 2004 | Interpreted | Sensitive |
| Groovy | 2003 | Interpreted | Sensitive |
| F# | 2005 | Native | Sensitive |
| PowerShell | 2006 | Interpreted | Fully Insensitive |
| Clojure | 2007 | Interpreted | Sensitive |
| Nim | 2008 | Native | Style-Insensitive (Ignores Case/Underscores) |
| Go | 2009 | Native | Sensitive + Semantic (Caps = Public) |
| Rust | 2010 | Native | Sensitive |
| Dart | 2011 | Native | Sensitive |
| Kotlin | 2011 | Native | Sensitive |
| Elixir | 2011 | Interpreted | Sensitive + Semantic (Module Naming Rules) |
| Julia | 2012 | Native | Sensitive |
| Elm | 2012 | Interpreted | Sensitive + Semantic (Case defines Type vs. Value) |
| TypeScript | 2012 | Interpreted | Sensitive |
| Swift | 2014 | Native | Sensitive |
| Crystal | 2014 | Native | Sensitive + Semantic (Caps = Constants) |
| Solidity | 2015 | Native | Sensitive |
| Zig | 2016 | Native | Sensitive |
| Raku | 2015 | Interpreted | Sensitive |
| Gleam | 2016 | Interpreted | Sensitive + Semantic (Caps = Types & Constructors) |
| V | 2019 | Native | Sensitive + Semantic (Forced Pascal/snake_case…) |
| C3 | 2019 | Native | Sensitive + Semantic (Case: Type, Const, Var, …) |
| Mojo | 2023 | Native | Sensitive |
Did I miss your favorite language?
With thousands of languages in existence, I’m sure a few notable ones slipped through the cracks.
If you notice a missing language or want to challenge my classification of a “quirky” one, let me know in the comments or reach out through the contact form.


