Module 1 · Variables, Types and Control Flow · Lesson 2 of 37
Value vs reference semantics, and method call stack frames
Value semantics and reference semantics are assignment rules
One concept
Value-type assignment copies data; reference-type assignment copies a reference to the same object.
Why this matters in TaskFlow
TaskFlow task objects will be passed around repositories, services, and UI code. Shared mutable objects can make a change appear in a completely different part of the system.
Mental model
Do not equate value type with stack or reference type with heap. The useful question is: what does assignment copy?
A value-type slot contains the data. A reference-type slot contains a reference. Copying the reference creates two aliases to one object.
MENTAL MODEL DIAGRAM
| value assignment | reference assignment |
|---|---|
| priorityA [ 2 ] | first [ ref 0xA ] --+ |
| priorityB [ 2 ] | second [ ref 0xA ] --+--> TaskCard |
| change B -> A unchanged | mutate through second -> first observes it |
TaskFlow: bad vs good
BAD - a copied reference is mistaken for a copied object
TaskCard first = new("Fix export");
TaskCard second = first;
second.Title = "Delete production";
Console.WriteLine(first.Title);GOOD - copy intent is explicit
TaskCard first = new("Fix export");
TaskCard second = new(first.Title);
second.Title = "Write regression test";
Console.WriteLine(first.Title); // Fix export
public sealed class TaskCard(string title)
{
public string Title { get; set; } = title;
}What beginners get wrong
They say 'classes live on the heap' and stop thinking. That does not explain aliasing, boxing, fields inside objects, or compiler optimizations.
What interviewers test
Predict aliasing behavior, explain shallow versus deep copy, and avoid the false stack-versus-heap shortcut.
What breaks in production
One request mutates an object cached or shared by another request, producing race conditions, stale views, and audit records that no longer match the original command.
Engineer question - answer before running code
What exactly does TaskCard second = first copy, and how many TaskCard objects exist afterward?
Mini refactor task
Add a Copy method or copy constructor to TaskCard. Demonstrate that changing the copy does not alter the original.
Constraint
Copy only the state currently present. Do not introduce records yet; make object creation explicit.
A method call creates a new stack frame story
One concept
Each active method call has its own logical frame containing parameters, locals, and a return point.
Why this matters in TaskFlow
When TaskFlow validation fails several calls deep, reading the stack trace depends on understanding who called whom and what each frame owned.
Mental model
Picture a stack of active conversations. The caller pauses at the call site. The callee receives parameter slots initialized from the arguments, creates local slots, and eventually returns a value or throws. The JIT may inline or optimize frames, but this model predicts source-level behavior and stack traces.
MENTAL MODEL DIAGRAM
top - currently running +----------------------------+ | NormalizeTitle(title slot) | | local: trimmed | +----------------------------+ | CreateTask(rawTitle slot) | | return point: line 12 | +----------------------------+ | Main(args slot) | +----------------------------+ bottom - oldest active call
TaskFlow: bad vs good
BAD - hidden global state makes call behavior unclear
static string _currentTitle = "";
static void NormalizeTitle()
{
_currentTitle = _currentTitle.Trim();
}GOOD - inputs and outputs tell the frame story
static string NormalizeTitle(string rawTitle)
{
string trimmed = rawTitle.Trim();
return trimmed;
}
string title = NormalizeTitle(" Fix export ");What beginners get wrong
They think a method 'jumps away' without tracking argument copies, locals, return values, or which frame an exception is leaving.
What interviewers test
Trace a call chain, identify parameter values, and read a stack trace from the throw site outward to callers.
What breaks in production
Hidden shared state makes methods order-dependent, tests flaky, and concurrent calls overwrite each other's data.
Engineer question - answer before running code
When NormalizeTitle starts, which frame owns rawTitle, which frame owns title, and what happens when the method returns?
Mini refactor task
Draw the frames for Main -> CreateTask -> NormalizeTitle. Put each parameter and local in the correct frame, then mark the return path.
Constraint
Use only data visible in the method signatures. Do not invent global fields.