GDKB

Namespaces

Beginner15 Minutes readUpdated July 21, 20262 related concepts

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.

On this page

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.Weapon always unambiguously refers to one specific type, regardless of what using statements are active — the short name Weapon is only ever a convenience shortcut for the full one.
  • using (C#) / using namespace (C++) bring a namespace's names into scope, so code can write Weapon instead of Game.Combat.Weapon everywhere in that file. If two usingd namespaces both define Weapon, the compiler reports an ambiguous-reference error rather than guessing.
  • Nesting mirrors project structure. Game.Combat.Weapons.Melee and Game.Combat.Weapons.Ranged read 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)

csharp
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;
    }
}
csharp
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)

cpp
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.

csharp
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 Manager in the same namespace are genuinely different concepts, CombatManager and UIManager is often clearer than nesting them into separate namespaces purely to allow the same short name.
  • using namespace at file/global scope in a C++ header, which leaks that namespace's names into every file that includes the header — usually reserved for .cpp files, 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 .cpp files 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

  1. Create two classes named Weapon in 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 plain using for both would fail to compile.
  2. Take an existing small script and wrap it in a namespace that mirrors its folder path. Explain what changed for callers in other files.
  3. Explain, from Blueprint's asset-path-based disambiguation, why Blueprint doesn't need an explicit namespace keyword the way C#/C++ do.
  4. 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.
  • 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

Related Concepts