Programming Fundamentals - Variables, Types, and Operators

A deep dive into the building blocks of every program — variables for storing data, types for describing its shape, and operators for combining it. Learn how memory, typing systems, and operator semantics work across languages.

10 min read
Programming FundamentalsVariablesTypesOperatorsBeginners

Programming Fundamentals - Variables, Types, and Operators

Every program — from a one-line script to a planet-scale distributed system — is built from three fundamental ideas: variables that hold data, types that describe what that data looks like, and operators that combine and transform it.

Master these three, and every language becomes easier to learn.


Variables

A variable is a named reference to a value stored somewhere in memory. The name lets you read and update the value without caring about its physical address.

age = 30          # name "age" points to the integer 30
name = "Alice"    # name "name" points to the string "Alice"
age = age + 1     # rebind "age" to a new integer (31)

How Variables Work in Memory

Conceptually, a variable is a label attached to a memory location:

Name        Address     Value
age   →     0x7ffc...   31
name  →     0x7ffd...   "Alice"

Different languages implement this differently:

  • C/C++: a variable IS the memory slot. Assignment overwrites the bytes.
  • Java/Python/JS: a variable is a reference to an object. Assignment changes which object the name points to.
a = [1, 2, 3]
b = a          # b points to the SAME list as a
b.append(4)
print(a)       # [1, 2, 3, 4] — both names see the mutation

Declaration vs. Initialization vs. Assignment

StepMeaningExample (TypeScript)
DeclarationIntroduce the namelet count: number;
InitializationGive it its first valuecount = 0;
AssignmentChange its value latercount = 5;

In many languages these happen in one line:

let count: number = 0;

Scope

Where a variable is visible in your program:

let global = 1;            // visible everywhere in this module

function outer() {
  let local = 2;           // visible only inside outer()

  if (true) {
    let block = 3;         // visible only inside this if-block
  }
  // console.log(block);   // ReferenceError — out of scope
}
  • Global scope: visible everywhere
  • Function scope: visible inside a function
  • Block scope: visible inside { ... } (added with let/const in JS)

Mutability — let vs const

let counter = 0;       // can be reassigned
counter = 1;           // OK

const PI = 3.14159;    // cannot be reassigned
// PI = 3.14;          // TypeError

const user = { name: 'Alice' };
user.name = 'Bob';     // OK — the binding is constant, the object is not
// user = {};          // TypeError — can't reassign the binding

Rule of thumb: default to const. Use let only when you genuinely need to reassign.

Naming Conventions

ConventionUsed ForExample
camelCaseVariables, functions (JS, Java)userName, totalCount
snake_caseVariables, functions (Python, Rust)user_name, total_count
PascalCaseClasses, typesUserProfile, OrderService
SCREAMING_SNAKE_CASEConstantsMAX_RETRIES, API_KEY

Good names describe intent, not implementation:

# Bad
d = 86400

# Good
seconds_per_day = 86400

Types

A type describes the shape of a value: what it can hold and what you can do with it. 5 + 5 makes sense; "hello" + true may or may not, depending on the language's rules.

Primitive Types

The atomic, indivisible types every language provides:

TypeExampleTypical Size
Integer42, -732 or 64 bits
Float / Double3.14, -0.00132 or 64 bits (IEEE 754)
Booleantrue, false1 bit (often padded to 8)
Character'a', '9'1 byte (ASCII) or 4 (Unicode)
String"hello"variable (sequence of chars)
Null / None / nilabsence of a valuelanguage-dependent

Composite Types

Built from primitives:

# List / Array — ordered collection
nums = [1, 2, 3, 4]

# Tuple — fixed-size, often immutable
point = (10, 20)

# Dictionary / Map / Object — key-value pairs
user = {"name": "Alice", "age": 30}

# Set — unordered, unique elements
tags = {"python", "web", "api"}

Static vs. Dynamic Typing

Static (C, Java, TypeScript, Rust, Go)Dynamic (Python, JavaScript, Ruby)
Type known at...Compile timeRuntime
Type errors caught...Before runningWhen the line executes
SpeedFaster — compiler optimizesSlower — type checks at runtime
FlexibilityMore verboseMore flexible, faster prototyping
// TypeScript — static
let age: number = 30;
age = "thirty"; // ❌ compile error
# Python — dynamic
age = 30
age = "thirty"  # ✅ runs fine — name now bound to a string

Strong vs. Weak Typing

Orthogonal to static/dynamic — about whether the language implicitly coerces types.

// JavaScript — weakly typed
"5" + 3      // "53"  (number coerced to string)
"5" - 3      // 2     (string coerced to number)
[] + {}      // "[object Object]"
# Python — strongly typed
"5" + 3      # TypeError: can only concatenate str to str

Type Inference

Modern static languages figure out types from context, so you write less:

let count = 0;          // inferred as number
const name = "Alice";   // inferred as string
const items = [1, 2, 3]; // inferred as number[]
let x = 42;             // inferred as i32
let pi = 3.14;          // inferred as f64

Type Casting / Conversion

Two flavors:

Implicit (automatic):

result = 5 + 3.14   # int 5 implicitly converted to float → 8.14

Explicit (you ask for it):

age_str = "30"
age_int = int(age_str)      # explicit conversion
price = float("19.99")
flag = bool(1)              # True
const n: number = Number("42");
const s: string = String(42);
const flag: boolean = Boolean(0); // false

Operators

Operators transform or compare values. They are the verbs of programming.

Arithmetic Operators

OpMeaningExampleResult
+Add5 + 38
-Subtract5 - 32
*Multiply5 * 315
/Divide10 / 33.33...
// or divInteger divide10 // 33
%Modulo (remainder)10 % 31
** or ^Exponent2 ** 101024

Watch out for integer division differences:

# Python 3
10 / 3   # 3.333... (float division)
10 // 3  # 3 (integer division)
// Java
10 / 3   // 3 (integer division — operand types decide)
10.0 / 3 // 3.333...

Comparison Operators

Return a boolean.

OpMeaning
==Equal
!=Not equal
<, >Less than, greater than
<=, >=Less or equal, greater or equal
5 == 5        # True
5 == "5"      # False  (different types)
[1, 2] == [1, 2]  # True  (deep equality)

JavaScript pitfall — == vs ===:

5 == "5"     // true  (coerces types — usually a bug)
5 === "5"    // false (strict equality — preferred)
null == undefined   // true
null === undefined  // false

Always use === in JavaScript unless you have a specific reason.

Logical Operators

Combine boolean expressions.

OpMeaning
&& or andBoth true
|| or orEither true
! or notNegation
is_admin = True
is_active = False

can_edit = is_admin and is_active   # False
can_view = is_admin or is_active    # True
is_blocked = not is_active          # True

Short-circuit evaluation — these stop as soon as the result is known:

const name = user && user.name;          // safely access .name
const port = process.env.PORT || 3000;   // fallback default

Bitwise Operators

Operate on individual bits — used in flags, low-level optimization, network protocols.

OpMeaningExample
&AND0b1100 & 0b1010 = 0b1000
|OR0b1100 | 0b1010 = 0b1110
^XOR0b1100 ^ 0b1010 = 0b0110
~NOT~0b1100 = ...11110011
<<Left shift1 << 3 = 8
>>Right shift8 >> 2 = 2
// Common pattern: feature flags as bitmask
const READ    = 0b001;  // 1
const WRITE   = 0b010;  // 2
const EXECUTE = 0b100;  // 4

let perms = READ | WRITE;            // 0b011
const canRead = (perms & READ) !== 0; // true

Assignment Operators

Shortcuts that combine assignment with another operation.

OpEquivalent
x += 5x = x + 5
x -= 5x = x - 5
x *= 5x = x * 5
x /= 5x = x / 5
x %= 5x = x % 5
x ||= yx = x || y (JS)
x ??= yx = x ?? y (JS, nullish)

Ternary / Conditional Operator

A compact if/else that returns a value:

const status = age >= 18 ? "adult" : "minor";
status = "adult" if age >= 18 else "minor"

Operator Precedence

When multiple operators appear, precedence decides which runs first:

2 + 3 * 4         # 14, not 20 — * before +
(2 + 3) * 4       # 20 — parens force order

True or False and False    # True — `and` before `or`

When in doubt, add parentheses. Clarity beats cleverness.


Putting It All Together

A small, realistic example using everything above:

// Calculate a shopping cart total with discount
interface CartItem {
  name: string;
  price: number;
  quantity: number;
}

function calculateTotal(items: CartItem[], discountPercent: number = 0): number {
  // Sum each item's subtotal
  let subtotal = 0;
  for (const item of items) {
    subtotal += item.price * item.quantity;  // arithmetic + assignment
  }

  // Apply discount only if it's in valid range
  const discount = discountPercent > 0 && discountPercent <= 100
    ? subtotal * (discountPercent / 100)
    : 0;

  const total = subtotal - discount;
  return Math.round(total * 100) / 100;  // 2 decimal places
}

const cart: CartItem[] = [
  { name: "Book", price: 15.5, quantity: 2 },
  { name: "Pen", price: 1.99, quantity: 5 },
];

console.log(calculateTotal(cart, 10));  // 36.86

This 20-line function uses variables (subtotal, discount, total), types (CartItem, number, string), arithmetic (+, *, -, /), comparison (>, <=), logical (&&), assignment (+=), and the ternary operator.

Once these three building blocks feel natural, every other language concept — control flow, functions, classes, modules — is just a way of organizing them.


Summary

  • Variables are named references to memory. Pay attention to scope and mutability.
  • Types describe what data is and what you can do with it. Know if your language is static/dynamic and strong/weak.
  • Operators transform and compare values. Know their precedence, and use parentheses when in doubt.
  • Most bugs in beginner code trace back to these basics: a wrong type, a leaked scope, or an unexpected operator coercion.

Next up: Control Flow — how to make these values move through your program.