9.2 Data Types, Variables & Identifiers
Key Takeaways
- Identifiers serve as human-readable labels for variables, constants, and subroutines; they must conform to language syntax rules (alphanumeric and underscores, never starting with a digit, no reserved keywords) and standard conventions (camelCase, PascalCase, snake_case, UPPER_SNAKE_CASE).
- Variables represent mutable memory locations whose stored values can be updated throughout program execution, whereas constants represent immutable storage locations locked upon initialization to prevent accidental logic corruption.
- Primitive data types define memory allocation footprints and permissible operations: Integers (signed vs unsigned whole numbers), Floating-Point numbers (IEEE 754 single and double precision decimals), Characters (single ASCII/Unicode symbols), Strings (ordered character sequences), and Booleans (logical truth values).
- Typing systems determine how strictly variable types are enforced: Statically typed languages verify types at compile time to catch mismatches early, whereas Dynamically typed languages evaluate types at runtime to maximize prototyping flexibility.
- Type casting transforms values between types: Implicit type coercion occurs automatically when widening without data loss, while Explicit type casting intentionally forces conversions, introducing risks of decimal truncation, precision loss, and integer overflow.
Data Types, Variables & Identifiers
Core Foundation: Every software application is fundamentally an information processing engine that manipulates data stored within computer memory. To manage this data reliably, programming languages provide structural abstractions: identifiers to label memory locations, variables and constants to manage mutability, primitive data types to define memory bit depths, and typing disciplines to enforce operational validity.
Identifiers: Syntax Rules vs. Naming Conventions
An identifier is a developer-defined textual token used to name a programming entity, such as a variable, constant, function, procedure, class, or data structure. Compilers and interpreters enforce rigid syntactic rules regarding identifiers, while software engineering organizations establish naming conventions to maintain codebase readability.
1. Mandatory Identifier Syntax Rules
If an identifier violates a language's syntax rules, the compiler or interpreter rejects the code with a syntax error:
- Permitted Characters: Identifiers may contain alphanumeric characters (uppercase letters
A–Z, lowercase lettersa–z, and digits0–9) and the underscore character (_). In some languages, characters like$are permitted for specific internal frameworks. - Cannot Begin with a Digit: An identifier must never begin with a numeric digit. For example,
userCount2and_tempValueare valid, but2ndUseror9livesare illegal syntax errors. This rule allows the compiler's lexical scanner to differentiate numeric literal values from variable names immediately. - Prohibition of Whitespace and Special Characters: Identifiers cannot contain spaces, hyphens, or punctuation marks (such as
-,.,@,!,#,?). A name likeuser-nameis parsed as subtraction (userminusname), not a single identifier. - Reserved Keywords are Forbidden: Identifiers cannot match the language's reserved keywords—words set aside by the language specification to define language grammar (e.g.,
if,else,while,for,class,return,int,true,false,switch). - Case Sensitivity: In virtually all modern high-level languages (C, C++, Java, C#, Python, JavaScript), identifiers are strictly case-sensitive. The identifiers
totalSales,TotalSales, andTOTALSALESrefer to three entirely separate memory locations.
2. Standard Identifier Naming Conventions
While compilers allow any identifier that satisfies the syntax rules, professional developers follow established casing conventions to signal the role and scope of an entity:
camelCase(Lower Camel Case): The initial word begins with a lowercase letter, and the first letter of each subsequent concatenated word is capitalized without spaces. Standard for variable names, object properties, and function/method names in JavaScript, Java, C#, and TypeScript.- Examples:
accountBalance,calculateTotalTax(),isCustomerVerified
- Examples:
PascalCase(Upper Camel Case): Every concatenated word begins with a capital letter, including the first word. Standard for class names, interfaces, custom data types, and C# method names.- Examples:
CustomerAccount,PaymentGateway,InventoryRecord
- Examples:
snake_case: All letters are written in lowercase, with concatenated words separated by an underscore (_). Standard for variable names, function names, and module filenames in Python, C, Ruby, and relational database table/column definitions.- Examples:
user_account_id,calculate_shipping_rate(),order_status
- Examples:
UPPER_SNAKE_CASE(Screaming Snake Case): All letters are written in uppercase, with words separated by underscores. Standard across almost all programming languages to designate constants (immutable values).- Examples:
MAX_RETRY_ATTEMPTS,PI,DEFAULT_TIMEOUT_MS,SALES_TAX_RATE
- Examples:
| Naming Convention | Capitalization Pattern | Typical Target Entity | Concrete Code Example |
|---|---|---|---|
| camelCase | First word lower, subsequent words capitalized | Variables, functions, object properties | let employeeHourlyRate = 28.50; |
| PascalCase | Every word capitalized | Classes, structs, interfaces, data types | class OrderProcessor { ... } |
| snake_case | All lowercase words separated by underscores | Python/C variables, database column names | user_session_token = "xyz123" |
| UPPER_SNAKE_CASE | All uppercase words separated by underscores | Immutable constants, global environment flags | const MAX_DB_CONNECTIONS = 100; |
Variables vs. Constants: Storage and Mutability
When a program executes, data is held in physical volatile memory (RAM). Variables and constants provide named abstractions over physical memory addresses.
Physical RAM Address: 0x7FFEED4B --> Value: 42 <-- Identifier: currentScore (Variable: Mutable)
Physical RAM Address: 0x7FFEED50 --> Value: 3.14 <-- Identifier: PI (Constant: Immutable)
1. Variables: Mutable Working Storage
A variable is a named storage location in memory whose assigned value can be changed, overwritten, or modified during program execution.
- When a variable is initialized, the operating system allocates a block of memory corresponding to the variable's data type.
- During execution, arithmetic operations, user input, or iterative loops can overwrite the data residing at that memory address.
- Example: A variable
itemsInCartstarts at0, increments to1when the user clicks "Add to Cart", and increments to3as shopping continues.
2. Constants: Immutable Guardrails
A constant is a named storage location in memory whose value is locked upon initialization and cannot be altered or reassigned during program execution.
- Languages enforce immutability through explicit keywords (such as
constin JavaScript, C, and C++;finalin Java; orvalin Kotlin). - If an instruction attempts to reassign a value to an established constant (e.g., attempting
MAX_USERS = 500;after declaringconst MAX_USERS = 250;), the compiler or interpreter throws an immediate fatal error. - Engineering Benefits of Constants:
- Prevents Accidental Logic Bugs: Guards critical configuration parameters, financial multipliers, and physical constants from being overwritten by rogue loops or errant functions.
- Eliminates "Magic Numbers": Replaces arbitrary numeric literals scattered throughout code with meaningful, centrally defined labels (e.g., using
MAX_LOGIN_ATTEMPTSinstead of repeatedly hardcoding the raw number3). - Compiler Optimization: Because the value never changes, compilers can replace constant references with direct literal values inside the machine instructions (inlining), boosting CPU execution speed.
Primitive Data Types and Memory Footprints
A data type defines the classification of data that a variable can hold. It instructs the compiler or interpreter on two critical parameters: how many bits of memory to allocate and what mathematical or logical operations are permissible on that data.
+--------------------------------------------------------------------------+
| PRIMITIVE DATA TYPE TAXONOMY |
| |
| +-------------------+ +--------------------+ +---------------+ |
| | NUMERIC | | TEXTUAL | | LOGICAL | |
| +-------------------+ +--------------------+ +---------------+ |
| │ │ │ │ │ |
| ▼ ▼ ▼ ▼ ▼ |
| [Integers] [Floats] [Character] [String] [Boolean] |
| (Whole #) (Decimals) (Single Glyph) (Text) (true/false) |
+--------------------------------------------------------------------------+
1. Integers (Whole Numbers)
Integers represent positive whole numbers, negative whole numbers, and zero, with no fractional or decimal components.
- Signed vs. Unsigned Integers:
- Signed Integers: Can represent both positive and negative values. The system utilizes Two's Complement binary encoding, reserving the Most Significant Bit (MSB, the leftmost bit) as a sign bit (
0for positive,1for negative). - Unsigned Integers: Can represent only zero and positive values. Because no bit is reserved for a sign flag, the maximum positive value is doubled compared to a signed integer of the identical bit depth.
- Signed Integers: Can represent both positive and negative values. The system utilizes Two's Complement binary encoding, reserving the Most Significant Bit (MSB, the leftmost bit) as a sign bit (
- Standard Bit Depths and Ranges:
- 8-bit Byte: Signed: $-128$ to $+127$. Unsigned: $0$ to $255$.
- 16-bit Short: Signed: $-32,768$ to $+32,767$. Unsigned: $0$ to $65,535$.
- 32-bit Integer (
int): The standard integer size on modern architectures. Signed: $-2,147,483,648$ to $+2,147,483,647$ (approximately $\pm 2.14$ billion). Unsigned: $0$ to $4,294,967,295$ (approximately $4.29$ billion). - 64-bit Long / BigInt: Signed: approximately $-9.22 \times 10^{18}$ to $+9.22 \times 10^{18}$ (quintillions). Used for enterprise financial ledgers, epoch microsecond timestamps, and massive database foreign keys.
2. Floating-Point Numbers (Decimals / Real Numbers)
Floating-point numbers represent real numbers that contain fractional decimal components or require scientific exponential notation (e.g., $3.14159$, $-0.0075$, $6.022 \times 10^{23}$).
- IEEE 754 Standard: Modern microprocessors implement the IEEE 754 standard for floating-point arithmetic. A floating-point number is partitioned into three binary components: a sign bit, an exponent, and a mantissa (fraction/significand).
- Single-Precision Float (32-bit): Allocates 1 sign bit, 8 exponent bits, and 23 mantissa bits. Provides approximately 7 decimal digits of precision.
- Double-Precision Float (64-bit /
double): Allocates 1 sign bit, 11 exponent bits, and 52 mantissa bits. Provides approximately 15 to 17 decimal digits of precision. Double precision is the default numeric decimal type in Java, C++, Python, and JavaScript. - The Floating-Point Inexactness Hazard: Binary floating-point cannot precisely represent certain base-10 fractions (such as $0.1$ or $0.2$), leading to micro-rounding discrepancies (e.g., evaluating $0.1 + 0.2$ in Python or JavaScript yields $0.30000000000000004$). For currency transactions and banking calculations, developers must never use standard floats; they use dedicated Fixed-Point or arbitrary-precision Decimal types (such as Java's
BigDecimalor Python'sdecimal.Decimal).
3. Characters (char)
A character represents a single alphanumeric glyph, typographic symbol, punctuation mark, or system control code.
- In code syntax, character literals are conventionally enclosed in single quotation marks (e.g.,
'A','7','$',' '). - ASCII Representation: Legacy 7-bit and 8-bit ASCII maps characters to numeric values from $0$ to $255$ (1 byte).
- Unicode Representation: Modern systems store characters using 16-bit code units (UTF-16) or variable 1-to-4 byte encodings (UTF-8), accommodating international alphabets, Asian ideographs, and emojis.
4. Strings
A string is an ordered sequence of characters treated as a unified data structure. In code syntax, strings are conventionally enclosed in double quotation marks (e.g., "CompTIA Tech+" or "user@example.com").
- Zero-Indexed Access: Individual characters within a string are accessed via a zero-based index. For string
text = "TECH",text[0]is'T',text[1]is'E',text[2]is'C', andtext[3]is'H'. - Concatenation: Combining two or more strings together sequentially using the concatenation operator (
+). For example,"Cyber" + "Security"evaluates to"CyberSecurity". - String Immutability: In many prominent high-level languages (including Python, Java, and C#), strings are immutable. When a string variable appears to be modified (e.g., converted to uppercase), the runtime does not alter the original memory buffer; it allocates an entirely new string object in memory.
5. Booleans (bool / boolean)
A Boolean represents a binary logical truth value: either true or false (conceptually 1 or 0).
- Booleans are named after English mathematician George Boole, who formulated Boolean algebra.
- Memory Storage Reality: Mathematically, a boolean requires only 1 single bit of information. However, because modern computer CPUs are built on byte-addressable memory architectures (memory addresses point to 8-bit bytes, not individual bits), most runtimes allocate an entire 8-bit byte to store a single boolean variable.
- Booleans serve as conditional flags that dictate control flow execution in branching statements (
if) and loops (while).
| Primitive Data Type | Typical Keywords | Memory Footprint | Representable Value Range / Precision | Concrete Literal Example |
|---|---|---|---|---|
| Integer | int, long, short | 16, 32, or 64 bits | Signed 32-bit: $-2.14\text{B}$ to $+2.14\text{B}$ | int userAge = 24; |
| Floating-Point | float, double | 32 bits (single) / 64 bits (double) | 64-bit double: $\sim 15\text{--}17$ decimal digits | double fuelPrice = 3.899; |
| Character | char | 8 bits (ASCII) / 16 bits (Unicode) | Single alphanumeric or punctuation symbol | char grade = 'A'; |
| String | string, String | Variable (1 byte per ASCII char + overhead) | Sequence of zero or more characters | string name = "Jordan"; |
| Boolean | bool, boolean | 8 bits (1 byte addressable storage) | Strictly binary truth states: true or false | bool isAuthenticated = false; |
Typing Systems: Statically Typed vs. Dynamically Typed
Programming languages enforce type safety through distinct typing disciplines that dictate when variable data types are established and validated.
1. Statically Typed Languages
In a statically typed language, variable data types are explicitly declared by the programmer (or statically inferred by the compiler) at the time of code creation, and are permanently locked during compilation.
- Compile-Time Verification: The compiler verifies type compatibility before generating machine binaries. If a developer attempts to assign a text string to an integer variable (e.g.,
int count = "five";), compilation halts with a fatal type error. - Representative Languages: C, C++, Java, Rust, Go, C#, and TypeScript.
- Advantages: Catches data mismatch bugs early in development before code reaches users; allows compilers to generate highly optimized, high-speed machine instructions; self-documenting code.
- Disadvantages: More verbose source code; requires explicit casting and longer initial development cycles.
2. Dynamically Typed Languages
In a dynamically typed language, variable types are not declared in source code. Types are bound to the underlying runtime values, not to the variable container itself.
- Runtime Evaluation: A variable can hold an integer, and later in the same execution thread be reassigned a string or a list. The interpreter tracks and verifies types dynamically as each statement executes.
- Representative Languages: Python, JavaScript, Ruby, and PHP.
- Advantages: Rapid prototyping; concise, flexible code syntax; lower barrier to entry for junior engineers.
- Disadvantages: Slower runtime execution due to continuous dynamic type checking; risk of runtime type crashes (such as
TypeErroror JavaScriptNaNvalues) occurring in production environments.
Type Casting: Implicit Coercion vs. Explicit Conversion
During software execution, programs frequently need to convert data from one data type to another. This process is known as type casting or type conversion.
Implicit Type Coercion (Widening - Safe): [int: 42] ───────> [double: 42.0] (Zero Data Loss)
Explicit Type Casting (Narrowing - Lossy): [double: 9.87] ───> [int: 9] (Fraction Truncated!)
1. Implicit Type Coercion (Automatic / Widening Conversion)
Implicit type conversion occurs automatically behind the scenes when the compiler or runtime converts a narrower data type into a wider data type without requiring programmer intervention.
- Widening Conversion (Safe): When an operation combines an integer and a floating-point number, the runtime automatically promotes the integer to a float because no mathematical precision is lost.
- Example: In Java or C++, evaluating
double total = 10 + 2.5;causes the integer10to implicitly convert to10.0, producing float12.5. - The JavaScript Coercion Trap: In loosely typed dynamic environments like JavaScript, implicit coercion can produce unexpected bugs. Evaluating
"5" + 2treats+as string concatenation, yielding the string"52". Conversely, evaluating"5" - 2coerces the string to a number, yielding the integer3.
2. Explicit Type Casting (Manual / Narrowing Conversion)
Explicit type casting occurs when the programmer deliberately commands the system to transform a value into a target data type using explicit casting syntax or conversion functions.
- Narrowing Conversion (Lossy): Converting a wider data type into a narrower data type (such as forcing a 64-bit float into a 32-bit integer).
- Syntax Examples:
- In C/Java:
int truncatedValue = (int) 9.87;(yields9) - In Python:
integer_count = int("42") - In JavaScript:
let numericScore = parseInt("100");
- In C/Java:
3. Critical Risks of Type Casting
- Truncation of Fractional Data: When a floating-point value is cast to an integer, the fractional decimal component is truncated (discarded entirely)—it is NOT mathematically rounded. Casting
9.99to an integer results in9, permanently losing the decimal precision. - Integer Overflow and Underflow: If a 32-bit integer with a large value is cast into an 8-bit byte (which can only hold values up to $255$), the high-order bits are sliced off. Casting decimal
300into an 8-bit unsigned byte causes the value to wrap around modulo 256, storing the unexpected value44($300 - 256 = 44$). - Parsing Exceptions: If a program attempts to parse non-numeric string data into an integer (e.g., executing
int("twenty")), the runtime will throw an unhandled parsing exception (ValueErrororNumberFormatException), crashing the application if unhandled.
A developer is writing code to calculate commercial freight costs. A fixed fuel surcharge multiplier of 1.15 must be referenced throughout hundreds of shipping calculation routines, but its value must be permanently protected against accidental modification during execution. According to industry best practices, how should this identifier be configured?
In common languages that use C-style identifier rules, which name begins with an illegal character and would cause a syntax error?
In a C-style statically typed language, a routine executes the narrowing cast int convertedVal = (int) 15.92;. What value is stored, and what happened?
Which primitive data type is specifically engineered to hold a single logical truth value representing exclusively either true or false?