← All posts
6 min read

Variables and Data Types: Naming Values and Defining Their Rules

#technology#computer-science#data-types#programming
📑 On this page

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,647

Exceeding 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.3

is false in JavaScript because of representation rounding.

For money, applications often store the smallest integer unit:

₹10.25 → 1025 paise

or 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:

  • null
  • undefined
  • 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.