Complete Guide | Lesson 2: Objects → Lesson 3: First Principles → Lesson 4: Classes (Apr 16)
Every bug you will ever write starts with a misunderstanding about what kind of thing you're holding.
You thought it was a number. It was a string. You thought it was a whole object. It was a reference to an object that somebody else already deleted. You thought it was there. It was null. And your program crashed at 3 AM while you were asleep, because you didn't understand types.
This is Lesson 3 of the Developer's Tree of Knowledge, and it maps to Kether on the Tree of Life. Kether means "Crown." It's the first sephira, the initial point of existence from which everything else emanates. In programming, that first point is the type system: the most fundamental decision you make about any piece of data. Before you build objects (Lesson 4), design inheritance hierarchies (Lesson 5), or architect systems (Lesson 12), you need to understand the atoms everything is made of.
Types are the periodic table of programming. Get them right and chemistry works. Get them wrong and things explode.
What Is a Type?
A type is a category of data. That's it. An integer is a type of data. A string of text is a type of data. True or false is a type of data. When you tell a program "this variable holds an integer," you're telling it what kind of thing to expect, what operations are valid on it, and how much memory to set aside.
The core types you'll encounter in every language:
Integer (int, long): Whole numbers. 1, 42, -17, 1000000. No decimal point. Used for counting, indexing, and anything where fractions don't apply. Your age is an integer. The number of items in your cart is an integer. The year is an integer.
Floating-point (float, double, decimal): Numbers with decimals. 3.14, 99.99, -0.001. Used for measurements, money (carefully), and scientific calculations. Your weight is a float. The price of a coffee is a float. Pi is a float that never ends.
String: Text. "Hello", "John Smith", "Error: file not found". Anything between quotes. Your name is a string. Your email address is a string. This entire paragraph is a string.
Boolean: True or false. Nothing else. Is the user logged in? Boolean. Is the light on? Boolean. Did the payment succeed? Boolean. The simplest type and arguably the most powerful, because every IF statement you wrote in Lesson 1 evaluates to a boolean.
Variables: Named Containers
A variable is a named box that holds a value of a specific type. customerAge = 34 creates a box labeled "customerAge," declares it holds an integer, and puts 34 inside.
Why naming matters: x = 34 works but tells you nothing. customerAge = 34 tells you everything. Six months from now, you'll look at your code and x could mean anything. customerAge is self-documenting. The best code reads like a story, not a math problem.
A constant is a variable that can never change after it's set. PI = 3.14159. MAX_LOGIN_ATTEMPTS = 3. TAX_RATE = 0.0825. Constants are boxes that are sealed shut after you fill them. Use them for values that should never change, because if someone accidentally changes your tax rate in the middle of a calculation, you'll spend a week finding the bug.
Value Types vs Reference Types (The Most Important Distinction in Programming)
This is the concept that most tutorials skip, most beginners never learn, and most bugs trace back to. Pay attention.
Value Types: The Photocopy
When you work with a value type (integers, booleans, floats), assigning one variable to another makes a copy. It's like handing someone a photocopy of a document. They can scribble on their copy all day. Your original is untouched.
1myAge = 34
2yourAge = myAge // yourAge gets a COPY: 34
3yourAge = 25 // only yourAge changes
4// myAge is still 34Two separate boxes. Two separate values. Changing one has zero effect on the other.
Reference Types: The House Address
When you work with a reference type (objects, arrays, complex structures), assigning one variable to another doesn't copy the data. It copies the address. It's like handing someone a piece of paper with your home address on it. You both now point to the same house. If they repaint it, you come home to a new color.
1myList = [1, 2, 3]
2yourList = myList // yourList gets the SAME ADDRESS
3yourList.add(4) // modifies the shared list
4// myList is now [1, 2, 3, 4] too!One house. Two people with the address. Changes made by either person affect both.
The Two Classic Bugs
Bug 1: "I changed it but it didn't change." You modified a copy of a value type and expected the original to update. It didn't. You were holding a photocopy. Bug 2: "I changed it and EVERYTHING changed." You modified a reference type through one variable and were surprised when the other variable saw the change too. You were both holding the address to the same house. These two bugs account for a staggering number of hours lost by junior developers. Understanding value vs reference types eliminates both.
Under the hood, this maps to two regions of memory: the stack (small, fast, holds value types and addresses) and the heap (large, flexible, holds the actual objects that reference types point to). You don't need to manage this manually in most modern languages, but understanding the model explains why value types and reference types behave differently.
Strong vs Weak Typing: The Compiler as Your First Code Reviewer
Here's where languages start to diverge, and where your choice of language becomes a philosophy, not just a preference.
Strong Typing: The Strict Parent
In a strongly typed language (C#, Java, TypeScript, Rust), the compiler refuses to let you mix types without explicit permission. If you try to add a number and a string, it stops you before the code ever runs.
1// C# or Java:
2int age = 34;
3String name = "Lee";
4int result = age + name; // COMPILER ERROR: can't add int and stringThe compiler catches your mistake at build time. You fix it before anyone sees it. The bug never reaches production.
Weak Typing: The Permissive Parent
In a weakly typed language (JavaScript, PHP), the runtime says "sure, I'll figure it out" and silently converts types behind your back. This is called type coercion, and it produces some of the most infamous behaviors in programming:
1// JavaScript:
2"5" + 3 // Result: "53" (string concatenation!)
3"5" - 3 // Result: 2 (numeric subtraction?!)
4"5" * "3" // Result: 15 (multiplication works on strings?!)
5true + true // Result: 2 (booleans are numbers now?!)JavaScript looked at "5" + 3, decided the + operator means string concatenation when a string is involved, and silently converted 3 to "3" and glued them together. Then for "5" - 3, it decided strings don't have a - operator, so it converted "5" to 5 and did math. Consistently inconsistent.
TypeScript exists specifically because JavaScript's weak typing caused so many problems that Microsoft built an entire language just to add a type system on top of it. TypeScript is JavaScript with a strict parent watching over your shoulder. It's the bridge between "move fast and break things" and "move fast and catch things before they break."
The Billion-Dollar Mistake
In 2009, Tony Hoare, the computer scientist who invented the null reference in 1965, gave a talk where he called it his "billion-dollar mistake." His exact words: "I call it my billion-dollar mistake. It was the invention of the null reference."
Null means "nothing." A variable that holds null doesn't hold zero. It doesn't hold an empty string. It holds the absence of any value at all. And when your code tries to use a null value as if it were a real object, it crashes. NullPointerException in Java. NullReferenceException in C#. TypeError: Cannot read property of null in JavaScript.
Null-related bugs are so common that modern languages have built entire features to prevent them:
Nullable types (C#): int? means "this might be an integer or it might be null." The compiler forces you to check before using it.
Optional (Java, Swift): Wraps a value that might or might not be present. You can't access the value without explicitly handling the "nothing" case.
Null safety (Kotlin, Dart): The compiler won't let you assign null to a variable unless you explicitly declare it as nullable.
The pattern is clear: the industry spent 50 years learning that null is dangerous, and now every new language ships with guardrails against it.
"I call it my billion-dollar mistake. It was the invention of the null reference in 1965. I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement." Tony Hoare said this, and every programmer who has ever chased a null pointer exception felt the weight of that confession.
Type Safety Quick Reference
Integer: Whole numbers. No decimals. For counting. Float/Double: Decimal numbers. For measuring. String: Text. For names, messages, labels. Boolean: True/false. For decisions. Null: Nothing. For pain. Value types: Copies when assigned. Changes are independent. Reference types: Shared address. Changes affect everyone. Strong typing: Compiler catches mistakes early. Weak typing: Runtime catches them late (or not at all).
Why This Matters for Everything Ahead
Every lesson from here forward builds on types. In Lesson 4, you'll learn that a class is a custom type you define yourself. In Lesson 5, inheritance is one type extending another. In Lesson 6, an interface is a type contract. In Lesson 9, generics let you write code that works for any type. Types aren't a beginner topic you outgrow. They're the atomic foundation that everything in software engineering rests on.