Data Types
Summary
A data type describes what kind of value a variable can hold and what operations are valid on it. It tells the compiler (or runtime) how many bytes to reserve, how to interpret those bytes, and which operations — addition, comparison, indexing — make sense. Every variable declaration pairs a name with a data type; choosing the right one is the first design decision every variable requires.
Mental Model
If a variable is a labeled box (see Variables), the data type is the box's shape and size, decided before anything is put inside. A box shaped for a whole number cannot hold a paragraph of text, and a box shaped for a single true/false flag cannot hold a 3D position.
Types come in two families:
- Value types ("plain boxes") — the box directly contains its
data. Copying the box copies the contents; each copy is independent.
int,float,bool, andstructtypes (Vector3) behave this way. - Reference types ("boxes holding an address") — the box contains directions to where the real data lives elsewhere. Copying the box copies the directions, not the destination — two boxes can point at the same underlying object, so changing the object through one box is visible through the other. Classes and arrays behave this way in C# and C++ (via pointers/references).
Knowing which family a type belongs to is the single most useful thing to know about it, because it predicts what happens on assignment.
Core Explanation
Data types are typically grouped as:
- Primitive / built-in types — the language's smallest building
blocks: integers (
int,long), floating point (float,double), boolean (bool), and character (char). These are almost always value types, fixed in size, and directly supported by the CPU. - Composite / structured types — built from primitives:
struct(C#) /struct-or-class(C++) group related fields together (Vector3is threefloats). Whether a composite type is a value type or reference type is a deliberate design choice, not automatic — C#'sstructis a value type, itsclassis a reference type, holding the same fields either way. - Reference / object types —
classinstances, arrays, strings (in most languages). The variable holds a reference to memory elsewhere (commonly heap-allocated), not the data itself. - User-defined types —
enums (a closed set of named values, e.g.Direction { Up, Down, Left, Right }), and the classes/structs the program itself declares (see Classes).
Static typing (C#, C++) checks that a value's type matches its variable's
declared type at compile time — a string cannot be assigned to an
int variable, and the program will not build until that is fixed. This
converts an entire category of runtime bugs into compile-time errors,
which is the primary value proposition of a static type system.
Type size matters for performance and memory: an int is 4 bytes, a
long is 8; choosing the smallest type that can safely hold every value
the variable will ever need reduces memory footprint, which matters at
scale (thousands of entities, each with several fields).
Implicit vs. explicit conversion. Some type conversions happen
automatically ("widening", e.g. int to float, because no information
is lost). Others require an explicit cast (float to int, because the
fractional part is discarded) — the language forces the programmer to
write the cast so data loss is visible in the code, not silent.
Syntax / Examples
C# (Unity)
int score = 0;
float speed = 5.5f;
bool isGrounded = true;
char grade = 'A';
string playerName = "Hero";
// Composite (value type)
Vector3 position = new Vector3(0f, 1f, 0f);
// User-defined enum
enum Direction { Up, Down, Left, Right }
Direction facing = Direction.Up;
// Explicit conversion — fractional part is discarded, not rounded
int wholeSpeed = (int)speed; // 5
C++ (Unreal)
int32 Score = 0;
float Speed = 5.5f;
bool bIsGrounded = true;
FString PlayerName = TEXT("Hero");
// Composite (value type)
FVector Position(0.f, 1.f, 0.f);
// User-defined enum
UENUM()
enum class EDirection : uint8 { Up, Down, Left, Right };
EDirection Facing = EDirection::Up;
int32 WholeSpeed = static_cast<int32>(Speed); // explicit, 5
Unreal Blueprint
Variable types are chosen from a dropdown in the My Blueprint panel
(Boolean, Integer, Float, Vector, a user-defined Enum asset, or another
Blueprint class as a reference type). An implicit widening conversion
(Integer → Float) is a straight wire; a narrowing conversion needs an
explicit conversion node, visually mirroring the cast above.
Practical Example
An inventory slot needs a stack count that can never exceed 999 and never
go negative — a small, bounded value, which argues for a small integer
type rather than the default int:
public class InventorySlot
{
public const int MaxStack = 999;
private ushort count; // unsigned short: 0..65535, plenty for 0..999
public void Add(int amount)
{
int result = count + amount;
count = (ushort)Mathf.Clamp(result, 0, MaxStack);
}
}
Choosing ushort over int here is deliberate: it documents "this value
is never negative and never large" directly in the type, and the cast back
to ushort after clamping makes the narrowing conversion visible rather
than implicit.
Common Mistakes
- Integer division truncation.
7 / 2in C# or C++ evaluates to3, not3.5, because both operands areint— the result is anint, and the fractional part is silently discarded. At least one operand must be a floating-point type (7 / 2.0f) to get a fractional result. - Overflow. Adding to an
intpast its maximum value wraps around to a large negative number (or throws, depending on build configuration) — it does not "become a bigger number." A running total that can plausibly exceed ~2.1 billion needs along, not anint. - Using
floatfor money or exact counts. Floating point cannot represent every decimal value exactly, so repeated arithmetic accumulates small errors. Anything requiring exact equality checks (currency, exact match conditions) should avoidfloatcomparisons via==and use integer types or an explicit tolerance instead. - Assuming a
structbehaves like aclass. Passing a largestructby value copies the whole thing on every function call — surprising both in behavior (mutating the copy doesn't mutate the original) and in performance (large structs should be passed by reference where the language allows it). - Comparing floating-point values for exact equality.
a == bon twofloats that were computed via different paths can befalseeven when they are "the same" mathematically, due to rounding. Compare with a small epsilon tolerance instead (Mathf.Approximatelyin Unity).
Best Practices
- Pick the smallest type that can safely hold every value the variable will ever need — not the largest "to be safe."
- Use
enuminstead of raw integers or strings for a closed set of named options; it is self-documenting and lets the compiler catch invalid values. - Make narrowing conversions explicit even when the language would allow an implicit one, so data loss is visible at the call site.
- Prefer
structfor small, short-lived, logically-value-like data (a 2D coordinate); preferclasswhen identity and shared mutation matter (an enemy, a save-game record). - Never compare floating-point values with
==; use an epsilon-based comparison.
Exercises
- Declare a variable to hold a player's remaining lives (0-9). Justify the type you chose over the alternatives.
- Predict, then verify, the result of
int result = 5 / 2;versusfloat result = 5 / 2f;and explain the difference. - Write an
enumfor a traffic light (Red,Yellow,Green) and a function that returns the next state given the current one. - Find a place in a sample project where a
floatis compared with==and rewrite it using an epsilon comparison.
Related Concepts
- Variables — data types are the "shape" half of every variable declaration.
- Operators — which operators are valid, and what they produce, depends on the operands' data types.
References
KNOWLEDGE_SCHEMA.md— GDKB's concept maturity ladder and cross-linking rules.- C# Language Reference — Built-in types: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types
- Unreal Engine — Property Types: https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-uproperties