If we were to take the work we’ve done so far and try to write a program, we couldn’t do much with it. See, we’ve done a lot of work in simplifying values, but don’t get me wrong, is important! However, notice even when describing some of the more hands on approaches in evaluating booleans, we ended up in a situation where we had to label things. This chapter will dive into this idea of labeling and remembering values, exploring
how we bind values to a label so that they become reusable,
whether these bindings are permanent or variable,
and how we define where we can use them.
Defining Our Terms
First, we introduce what we call these labeling/bindings: variables.
Variables
Definition
A Variable is a reserved space in memory used to store a value of some type.
When we want to label a value in programming, we usually create a variable for it. We refer to giving a value to this variable as binding or assigning the value to it.
Properties
Memory Management: Types define the exact amount of memory space needed for each variable, allowing C# to efficiently allocate and manage computer resources
Program Reliability: Fixed types prevent unexpected behavior by ensuring operations (like division) consistently work as intended across your code
Example
int x = 7; // reads: create an int variable called x, and assign 7 to it.
Notice that we use the = symbol here. In C# = is used for assignment, where is == is used to check for equality.
Exercises - Code Correction (5 problems)
Fix invalid C# code by addressing syntax/type errors
Task: Fix 3 type mismatches. Explain proper literals.
Memory Management
When you create a variable, C# needs to plan ahead for the space it’ll occupy in memory. It’s like reserving a specific size storage unit - you need to know exactly how much space you’ll need:
int age = 25; // 32 bits reserveddouble salary = 50000.00; // 64 bits reserved
Memory Allocation
Each type declaration gives C# precise instructions for memory allocation. No guesswork needed - just clean, efficient storage.
Type Safety
Type consistency ensures your operations behave predictably across your codebase. Consider division:
The guarantee that operations will behave consistently based on their types, preventing unexpected bugs and crashes.
Practical Impact
In real applications, type safety becomes crucial. Financial calculations, data processing, or any situation where precision matters - having guaranteed behavior makes your code reliable and maintainable.
Think of types as both an organizational system and a safety net. They help C# manage memory efficiently while ensuring your operations remain consistent and predictable throughout your code.
Exercises - Output Prediction (5 problems)
Predict console output then verify
1. Code:
int a = 5, b = 3;double result = a / b;Console.WriteLine(result);
Task: Predict output. Why is it not 1.666…, and how can we modify the code to get 1.666...?
2. Code:
int x = 10;x = x + x * 2;Console.WriteLine(x);
Task: Predict the final value of x. Explain the order of operations (multiplication vs. addition).
3. Code:
string s = "7";int n = 3;Console.WriteLine(s + n + n);
Task: Predict output. Explain how string concatenation works when combining strings and numbers.
4. Code:
double d = 1/2 + 1.0/2;Console.WriteLine(d);
Task: Predict result. How do integer and floating-point divisions differ? Fix it so the output is 1.0.
5. Code:
Console.WriteLine(10 - 2 * 3 + 5);
Task: Predict the output. Show the operator precedence steps (multiplication vs. addition vs. subtraction).
Now you may have noticed that we use the word variable. This seemingly implies that the value held can, well, vary. This is true! C#‘s variables may be re-assigned/bound by default. To cover cases where this is not desired, the const keyword is used.
Example
int x = 7;x = 15; // this is valid// However...const int y = 7;y = 0; // this will cause an error
We now have this idea that a variable’s value can change throughout the execution of your program. After line 1, x == 7 would return true, however after line 2 it would return false. This means if I hand you this code and ask: “What value does x have”, both 7 and 15 would be valid answers. To handle this, when we talk about code, we need to be specific about the place in our program we are referring to. This allows us to talk about our code in different states.
State
Definition
Program state is the set of bindings at a given point of execution.
We can refer to the set of variables and their current values as our bindings.
Example
int x = 37;int y = 12;bool isBigger = false;isBigger = x <= y;x = 12isBigger = x <= y;
After line 1 runs, 37 is bound by x.
After line 2, 12 is bound by y.
Depending on if we check after line 3 or line 8 runs, isBigger will be either false or true respectively.
To handle this we introduce using a table to track the program state:
after line # runs
x
y
isBigger
1
37
-
-
2
37
12
-
3
37
12
false
5
37
12
false
7
12
12
false
8
12
12
true
This let’s us talk about what the data in our program is like at any point, which, now that this can change wildly line per line, seems pretty handy to me. This also let’s us do something nice: we can now look at how this data changes to better understand what our code is doing. Instead of a bunch of expressions we try to follow, we can also look at how the state of our program changes over time to better understand how it works. This is incredibly useful when debugging code, where we often end up programming behavior wrong, and the only way to see that is to find that our stored values are off!
Exercises - State Tracing (5 problems)
Create variable state tables
1. Code:
int a = 5;a += 2;int b = a + 2;bool eq = (a == b);
Task: Track values after each line.
2. Code:
string s = "Hi";s += " there";int len = s.Length;bool empty = (len == 0);
Task: Show state evolution.
3. Code:
int x = 10, y = 5;x = y;y *= 2;bool test = (x > y);
Task: Create state table with comments.
4. Code:
double d = 3.5;int i = (int)d;d = i / 2.0;
Task: Track types and values.
5. Code:
bool a = true, b = false;bool c = (a == b);a = !c;
Task: Show boolean state changes.
[!info] Fillable State Table
You might create a table like below to record each variable’s state after each line.
Unfilled State Table
Line
a
b
eq
Notes
1
int a = 5;
2
a += 2;
3
int b = a + 2;
4
bool eq = (a == b);
Now there may be some question about how this works under the hood. Well, notice that when we define a variable, we must give it a type. This is important: Programming languages use types not only to define what kind of value something will be, but also how much space it will take. So when we create a variable, C# first looks at the type, remember an int is a 32bit whole number, right? Well, C# will find a 32-bit chunk of memory and reserve it for your variable. We also need to name it: this name is how C# finds the variable in memory, this is how it determines its address.
However, this raises a question: if we are reserving space in memory for these variables, how/when are they ever freed?
C# uses what’s called a garbage collector, to detect when a variable will not be used again in the program, “releasing” it from memory thereafter.
C# also recognizes that it can be nice to have manual control over this as well, providing tools to allow us to control where a variable will be available explicitly, rather than letting the garbage collector take all the fun from us. It does so using the concept of define scopes.
Scope
Definition
Program scope hold boundaries of code, with a defined start and end, where any new entries to the programs state are cleared once execution crosses the end.
This means that any variable, or other binding, we create within a specific scope is only accessible within, and inaccessible from the outside.
curly braces{} to define the bounds of scope.
{int x = 17;x > 1; // this works}{int y = 18y = x; // this doesn't, x doesn't exist outside of the scope it belongs to}
Exercises - Scope Identification (5 problems)
Find and fix scope violations
1. Code:
{ int secret = 42;}Console.WriteLine(secret);
Task: Diagnose the error. Propose two fixes (e.g., declare secret outside the block).
2. Code:
{ string name = "Alan";}name = "Alice";Console.WriteLine(name);
Task: Identify issue. Rewrite so name remains accessible where it’s needed.
3. Code:
Evaluation Priority
Variables always resolve to their current values before any operations execute.
Exercises - Evaluation Sequencing (5 problems)
Step through expression evaluation
1. Code:
int a = 3;int b = a * a + 2;
Task: Show evaluation steps (order of multiplication, addition, assignment). Final values?
2. Code:
int x = 5;int y = x + 2 * x;x = y - x;
Task: Trace the order of operations and assignments. Final x and y?
3. Code:
double d = (int)2.9 + Math.Ceiling(1.1);
Task: Break down evaluation sequence. Which part runs first? Why?
4. Code:
string s = "a" + 1 + 2;string t = 1 + 2 + "a";
Task: Explain how each expression is evaluated. Why do we get different results?
5. Code:
int a = 1, b = 2, c = 3;a = b = c;
Task: Show right-to-left assignment flow (i.e., b = c then a = b).
Core Principles:
Variables serve as value proxies in expressions
Complete evaluation precedes any assignment
Type compatibility is rigorously enforced
Complex expressions resolve variables before performing operations
In general, you will find that many errors you run into come from not considering what order things will evaluate in. Now that we have this concept of program state and storing values, how do we create programs that change behavior based on these variables? Next chapter we will cover this, going over Branching as a control flow structure.