Namespaces
Summary
A namespace groups related types under a shared, dotted name
(Game.Combat.Weapons) so that two unrelated types can both be called
Weapon without colliding, and so a codebase's structure is visible from a
type's fully-qualified name alone. Namespaces exist purely to organize and
disambiguate — they add no runtime behavior of their own.
Mental Model
A namespace is like a postal address system for code. Two people can both
be named "Alex" without any confusion, because a full address (street,
city, country) disambiguates them — nobody needs a globally unique first
name. A class called Weapon inside Game.Combat and a different class
also called Weapon inside Editor.Tools can coexist for the same
reason: their full "addresses" (Game.Combat.Weapon vs.
Editor.Tools.Weapon) are different, even though the short name collides.
A using Game.Combat; (C#) statement is like saying "for the rest of this
conversation, when I say 'Alex' I mean the one on Combat Street" — it lets
code refer to a type by its short name within a scope where that shortcut
is unambiguous.
Core Explanation
- Purely organizational, zero runtime cost. A namespace does not affect how code executes, how much memory a type uses, or performance in any way — it exists entirely at compile time, to organize names and resolve which type a short name refers to.
- Fully-qualified names are always valid.
Game.Combat.Weaponalways unambiguously refers to one specific type, regardless of whatusingstatements are active — the short nameWeaponis only ever a convenience shortcut for the full one. using(C#) /using namespace(C++) bring a namespace's names into scope, so code can writeWeaponinstead ofGame.Combat.Weaponeverywhere in that file. If twousingd namespaces both defineWeapon, the compiler reports an ambiguous-reference error rather than guessing.- Nesting mirrors project structure.
Game.Combat.Weapons.MeleeandGame.Combat.Weapons.Rangedread as a hierarchy the same way folder paths do, and commonly do mirror the folder layout on disk, though the language does not require that correspondence.
Syntax / Examples
C# (Unity)
namespace Game.Combat
{
public class Weapon
{
public float Damage;
}
}
namespace Editor.Tools
{
public class Weapon // A distinct type — no collision with Game.Combat.Weapon.
{
public string ToolName;
}
}
using Game.Combat;
public class Loadout : MonoBehaviour
{
public Weapon Primary; // Resolves to Game.Combat.Weapon via the `using`.
void Start()
{
// Fully-qualified form always works too, `using` or not:
Editor.Tools.Weapon tool = new Editor.Tools.Weapon();
}
}
C++ (Unreal)
namespace Game::Combat
{
struct FWeaponStats
{
float Damage;
};
}
using namespace Game::Combat;
void ULoadout::Init()
{
FWeaponStats Stats; // Resolves via `using namespace Game::Combat`.
Stats.Damage = 25.0f;
// Fully-qualified form:
Game::Combat::FWeaponStats Explicit;
}
Note: Unreal Engine's own C++ codebase does not heavily use C++
namespaces for gameplay classes (its naming-prefix convention — A for
Actors, U for UObjects, F for plain structs — serves a related but
distinct disambiguation role); namespaces are still valid and used for
utility/library code within Unreal C++ projects.
Unreal Blueprint
Blueprint has no namespace construct. Two Blueprint classes cannot share a name in the same project at all — Blueprint disambiguates purely through asset paths (folder location) instead, which is a similar idea (a hierarchical "address") without exposing it as a language feature.
Practical Example
A project has both a gameplay Inventory system and a debug/editor-only
Inventory inspection tool. Namespaces keep them from colliding while
making the intent of each visible from its full name.
namespace Game.Systems
{
public class Inventory
{
public List<string> Items = new List<string>();
}
}
namespace Game.DebugTools
{
public class Inventory // A debug overlay, unrelated to the gameplay type.
{
public void DrawOverlay(Game.Systems.Inventory target) { /* ... */ }
}
}
Game.DebugTools.Inventory.DrawOverlay takes a
Game.Systems.Inventory parameter — the fully-qualified reference inside
the method makes it unambiguous which Inventory is meant, even without a
using statement, and reading the parameter type alone documents the
relationship between the two otherwise-identically-named classes.
Common Mistakes
- Reaching for a namespace to fix a naming collision that a better name
would fix. If two types named
Managerin the same namespace are genuinely different concepts,CombatManagerandUIManageris often clearer than nesting them into separate namespaces purely to allow the same short name. using namespaceat file/global scope in a C++ header, which leaks that namespace's names into every file that includes the header — usually reserved for.cppfiles, not headers, to avoid silent collisions in unrelated code that happens to include this one.- Assuming a namespace implies an assembly/module boundary. A namespace is just a naming device — it does not control what's public/private, what can be unloaded independently, or how code is packaged. That's the job of access modifiers ([[CON-0020]]) and the project/assembly structure respectively.
- Deeply nesting namespaces without a clear reason (
Game.Systems. Combat.Weapons.Melee.OneHanded.Swords) — past a certain depth, the organizational benefit is outweighed by the friction of typing and reading fully-qualified names.
Best Practices
- Mirror the namespace hierarchy to the project's folder structure so a type's location on disk and its fully-qualified name tell the same story.
- Use namespaces to separate genuinely distinct areas of a codebase (gameplay vs. editor tooling vs. tests), not as a substitute for descriptive class names within a single area.
- Keep
using namespace(C++) out of headers; scope it to individual.cppfiles where the shortcut is actually used. - Prefer a small number of well-named top-level namespaces over deep, narrow nesting — organize for readability, not for the sake of hierarchy.
Exercises
- Create two classes named
Weaponin different namespaces (as in the Core Explanation example) and write a third file that references both by their fully-qualified names in the same method. Explain why a plainusingfor both would fail to compile. - Take an existing small script and wrap it in a namespace that mirrors its folder path. Explain what changed for callers in other files.
- Explain, from Blueprint's asset-path-based disambiguation, why Blueprint doesn't need an explicit namespace keyword the way C#/C++ do.
- Identify a case (real or hypothetical) where a namespace was used to solve a naming collision that a more descriptive class name would have solved more simply, and rewrite it that way.
Related Concepts
- Access Modifiers — namespaces organize names; access modifiers control visibility. The two are frequently confused but solve different problems.
- Functions — a namespace can also hold free functions/utilities (not just types), organized the same way as classes are.
References
KNOWLEDGE_SCHEMA.md— GDKB's concept maturity ladder and cross-linking rules, which this document follows.- Unity/.NET — Namespaces (C# Programming Guide): https://learn.microsoft.com/dotnet/csharp/fundamentals/types/namespaces
- Unreal Engine C++ documentation — Coding Standard, naming conventions: https://dev.epicgames.com/documentation/en-us/unreal-engine/epic-cplusplus-coding-standard-for-unreal-engine