Variables and Data Types: Naming Values and Defining Their Rules
📑 On this page
- Bindings and values
- Why names matter
- Primitive types
- Integer ranges
- Floating-point values
- Strings and text
- Composite types
- A concrete checkout example
- Static and dynamic typing
- Type inference
- Scope
- Mutability
- Nullability and absence
- Conversion and coercion
- Common misunderstandings
- "A variable is a box containing a value"
- "All numbers behave the same"
- "Static typing means no runtime type errors"
- "const makes every nested value immutable"
- Knowledge check
- The one idea to remember
Programs need to remember intermediate results and describe what kind of information each result represents.
Two ideas provide that structure:
A variable associates a name with a value or storage location. A data type defines a category of values, their representation, and valid operations.
Names make logic readable. Types prevent the same bits from being interpreted arbitrarily.
Bindings and values
Consider:
let quantity = 3;quantity is a name bound to the number value 3.
Later:
quantity = 4;changes the binding's current value.
Language details differ. A variable can refer to:
- Value stored directly
- Object reference
- Memory location
- Immutable binding
The conceptual purpose is stable: give program data a useful name.
Why names matter
Compare:
const x = p * q;with:
const subtotal = unitPrice * quantity;Both can calculate the same result. The second preserves business meaning.
Good names reduce the amount of context a reader must hold mentally.
Names should describe role rather than implementation history.
Primitive types
Languages commonly provide types such as:
- Integer
- Floating-point number
- Boolean
- Character
- String
An integer supports discrete whole values. A Boolean represents true or false.
The type determines:
- Allowed values
- Memory representation
- Operators
- Conversion behavior
- Range and precision
Adding numbers differs from concatenating strings even if both use a + symbol.
Integer ranges
A fixed-width unsigned eight-bit integer holds 0 through 255.
A signed 32-bit integer commonly holds:
-2,147,483,648 through 2,147,483,647Exceeding the range can:
- Wrap
- Trap
- Promote
- Produce language-specific behavior
Security bugs can arise when size calculations overflow and allocate less memory than expected.
Choose numeric types according to range and failure behavior.
Floating-point values
Floating-point types represent a wide range of fractional values using finite binary precision.
Decimal 0.1 cannot be represented exactly in common binary floating-point.
0.1 + 0.2 === 0.3is false in JavaScript because of representation rounding.
For money, applications often store the smallest integer unit:
₹10.25 → 1025 paiseor use decimal arithmetic types.
The correct choice depends on required precision and operations.
Strings and text
A string is a sequence representing text.
Important questions include:
- Encoding
- Length unit
- Immutability
- Comparison rules
- Locale
- Normalization
User-perceived characters can contain several Unicode code points.
Alphabetical sorting depends on language and collation rules, not simple numeric code-point order.
Treating text as raw bytes or ASCII creates internationalization bugs.
Composite types
Programs combine values into structures.
Example:
type Product = {
id: string;
name: string;
priceInPaise: number;
available: boolean;
};Composite types model domain concepts and ensure related fields travel together.
Other structures include:
- Arrays
- Tuples
- Maps
- Sets
- Enumerations
- Classes
- Tagged unions
The structure chosen affects lookup, ordering, uniqueness, and allowed states.
A concrete checkout example
const quantity: number = 2;
const unitPriceInPaise: number = 49900;
const customerName: string = "Asha";
const hasValidAddress: boolean = true;
const subtotal = quantity * unitPriceInPaise;Each variable has a role and type.
Representing price as integer paise avoids binary decimal rounding.
An order type can require both currency and amount so values from different currencies are not added accidentally.
Types become a design language for valid business states.
Static and dynamic typing
With static typing, many type relationships are checked before execution.
With dynamic typing, values carry runtime types and operations are checked during execution.
Both can be safe or unsafe depending on design and tooling.
Static systems can catch mismatches earlier and improve refactoring.
Dynamic systems offer flexibility and concise exploratory code.
Gradual typing adds optional static analysis to dynamic languages.
Type inference
Static types do not require writing every annotation.
A compiler can infer:
const count = 3;as a number.
Explicit annotations are useful at public boundaries, complex structures, and places where intent is not obvious.
Excessive annotations repeat information; too few can hide important contracts.
Scope
Scope determines where a name is visible.
Possible scopes include:
- Block
- Function
- Module
- Class
- Global
Narrow scope reduces accidental interaction.
A local variable can use a concise name understood within a few lines. A global variable affects distant code and needs stronger justification.
Name shadowing occurs when an inner scope reuses an outer name, which can be useful or confusing.
Mutability
A mutable value can change after creation. An immutable value cannot.
Immutability simplifies reasoning:
- No hidden changes
- Safer sharing
- Easier concurrency
- Predictable history
Mutation can be efficient and natural for local state.
Many languages distinguish an immutable binding from an immutable object. A constant reference may still point to an object whose fields change.
Nullability and absence
Programs need to represent missing values.
Options include:
nullundefined- Optional types
- Result types
- Sentinel values
Using 0, empty string, or -1 as a missing marker can conflict with legitimate values.
Type systems that explicitly represent absence force callers to handle it.
Uncontrolled null references are a common source of runtime errors.
Conversion and coercion
Conversion changes a value's type.
Explicit:
const count = Number(input);Implicit coercion happens automatically:
"5" + 1 // "51"Validate conversion results. Number("hello") produces a non-number value rather than useful input.
At system boundaries, parse strings into domain types once and reject invalid forms early.
Common misunderstandings
"A variable is a box containing a value"
The box analogy helps initially, but variables can be bindings to references, immutable values, or compiler abstractions.
"All numbers behave the same"
Integers, floating point, decimals, and arbitrary-precision values differ in range and precision.
"Static typing means no runtime type errors"
External data, unsafe operations, reflection, and logic mistakes still require runtime validation.
"const makes every nested value immutable"
In many languages it prevents rebinding, not mutation of the referenced object.
Knowledge check
1. What does a data type define?
A category of values, their representation or interpretation, and valid operations.
2. Why is binary floating point risky for exact money calculations?
Many decimal fractions cannot be represented exactly, creating rounding differences.
3. What is scope?
It is the region of a program where a name is visible and usable.
4. Why represent absence explicitly?
It prevents missing data from being confused with legitimate values and forces handling at relevant boundaries.
The one idea to remember
Variables give values meaningful names; data types define what those values are allowed to represent and do.
Good type choices preserve domain meaning, range, precision, mutability, and absence rules before bugs reach deeper logic.
Next, we will use Boolean expressions and conditions to turn values into program decisions.