Struct Vs Class When To Use Which Β· Additional notes

3 min read
Mid-level7 min read
Rapid overview

Additional notes

βš™οΈ Practical Explanation (How CLR Handles Them)

🧩 struct

  • Lives inline β€” if it’s a local variable, it’s on the stack; if it’s a field in another object, it’s inside that object’s memory layout.
  • When passed to a method, a full copy is made (unless passed by ref or in).
  • Ideal for small, immutable, lightweight data β€” e.g., coordinates, ticks, prices, GUIDs.

Example:

struct Point
{
    public int X;
    public int Y;
}

Each Point lives inline β€” no GC pressure.


🧩 class

  • Lives on the managed heap. Variables hold a reference (pointer) to the actual object.
  • Passed around by reference, so multiple variables can point to the same instance.
  • Managed by the Garbage Collector.

Example:

class Order
{
    public string Symbol { get; set; }
    public double Price { get; set; }
}

Each Order allocation hits the heap and is tracked by the GC.


⚑ Performance and Design Implications

βœ… When to use struct

Use when:

  • The object is small (≀ 16 bytes typically).
  • It’s immutable.
  • You’ll create many of them (e.g., millions per second) and want no GC overhead.
  • Value semantics make sense (copying creates independence).

Example (trading context):

readonly struct Tick
{
    public string Symbol { get; }
    public double Bid { get; }
    public double Ask { get; }
}

Each Tick represents an immutable market data point. Perfect as a struct.


🚫 When NOT to use struct

Avoid when:

  • It’s large (lots of fields) β†’ copying becomes expensive.
  • You need polymorphism, inheritance, or shared references.
  • You mutate the same instance in multiple places.

⚠️ Boxing and Hidden Allocations

When a struct is treated as an object or cast to an interface, it gets boxed β€” copied onto the heap.

struct Point { public int X, Y; }

object obj = new Point(); // BOXED: allocates on heap
Point p = (Point)obj;     // UNBOXED: copy back to stack

So: value types are not automatically zero-GC β€” you must use them carefully.


🧩 Memory Visualization

Stack:
 β”œβ”€ Tick t1 { X=1, Y=2 }   (struct: inline)
 β”œβ”€ Tick t2 = t1 (copied!)
 └─ Order ref ─┐
               β–Ό
Heap:
 └─ { Symbol="EURUSD", Price=1.0734 }  (class: heap object)

1️⃣ Basic memory layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Stack               β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚ β”‚ int x = 10;             β”‚  β”‚
β”‚ β”‚ Point p = {X=1,Y=2};    β”‚  β”‚  ← Struct (value type)
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚   (lives inline here)        β”‚
β”‚                              β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚ β”‚ Order o ────────────────┼──┼──► Heap
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Heap               β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚ β”‚ Order { Id=1, Price=99 }β”‚  β”‚  ← Class (reference type)
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Explanation:

  • Struct (Point) is stored directly on the stack or inline within another object.
  • Class (Order) is stored on the heap; variables on the stack hold a reference (pointer) to it.

2️⃣ Assignment behavior

βœ… Struct (value type)

Point a = new Point { X = 1, Y = 2 };
Point b = a;    // copy!
b.X = 99;
Console.WriteLine(a.X); // 1 (a unaffected)

Memory:

Stack:
 a { X=1, Y=2 }
 b { X=99, Y=2 }   ← completely separate copy
  • Structs are copied by value.
  • Each variable has its own independent copy.
  • No heap allocation β†’ no GC pressure.

βœ… Class (reference type)

Order o1 = new Order { Id = 1, Price = 99 };
Order o2 = o1;  // copy reference!
o2.Price = 120;
Console.WriteLine(o1.Price); // 120

Memory:

Stack:
 o1 ─┐
 o2 β”€β”˜β”€β”€β–Ί Heap: { Id=1, Price=120 }
  • Classes are copied by reference β€” both variables point to the same heap object.
  • Modifying one affects the other.

3️⃣ Struct inside a class (inline layout)

class Trade
{
    public string Symbol;
    public Point Position;
}

Memory:

Heap: Trade
 β”œβ”€ Symbol β†’ "EURUSD"   (heap reference)
 └─ Position { X=10, Y=20 }  (inline in Trade object)

Insight: Even though the struct is inside a class (on heap), its fields are embedded inline β€” not separate allocations. This reduces pointer indirection and helps cache locality.


4️⃣ Passing to methods

void Move(Point p) { p.X += 10; } // copy!
void MoveRef(ref Point p) { p.X += 10; } // modifies original

Memory visualization:

By value (copy):
 Caller: a { X=1 }
 Method: p { X=1 } β†’ modified to X=11 (copy destroyed)

By ref:
 Caller: a { X=1 }
 Method: p ─┐
             └─ modifies same memory β†’ X=11 persists

πŸ’‘ Interview tip:

β€œStructs are copied on method calls unless passed by ref or in. Large structs should be passed by in to avoid copy overhead β€” especially in tight loops or latency-critical code.”


5️⃣ Heap fragmentation and GC difference

Structs:
[Stack]
[Stack frame destroyed β†’ data gone instantly]
β†’ No GC involvement.

Classes:
[Heap]
[Objects live until unreachable]
β†’ GC scans and collects them (Gen0β†’Gen1β†’Gen2)

Key insight:

  • Structs vanish when they go out of scope β†’ predictable lifetime.
  • Classes depend on GC cycles β†’ non-deterministic reclamation.
  • Overusing classes in a high-frequency path (like market ticks) causes GC churn and pauses.

🧠 Quick β€œwhiteboard pitch” for your interview

β€œStructs are value types β€” stored inline, copied by value, no GC involvement, ideal for small immutable data like ticks or coordinates. Classes are reference types β€” heap-allocated, reference-based, and managed by GC. I use structs where I want predictable lifetimes and zero allocations; classes when I need shared, long-lived state or polymorphism.”


Would you like me to now create a visual of memory layout with stack/heap arrows (an actual diagram you could memorize or even sketch during the interview)? It would show struct, class, and mixed cases (struct-in-class, class-in-struct) clearly.

See also