Skip to content

Commit 9730696

Browse files
committed
Add constructors-and-invariants parity module for C#, Go, and Python
1 parent fbc147e commit 9730696

26 files changed

Lines changed: 593 additions & 13 deletions

File tree

LANGUAGE_PARITY_MATRIX.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ Current parity progress in non-C++ tracks:
4242

4343
Current parity progress in non-C++ tracks:
4444

45-
- C#: `1/5` modules complete in `03-advanced`
46-
- Go: `1/5` modules complete in `03-advanced`
47-
- Python: `1/5` modules complete in `03-advanced`
45+
- C#: `2/5` modules complete in `03-advanced`
46+
- Go: `2/5` modules complete in `03-advanced`
47+
- Python: `2/5` modules complete in `03-advanced`
4848

4949
### Advanced (`03-advanced`) - Current Expansion Queue
5050

5151
| Order | Module | C++ | C# | Go | Python |
5252
| --- | --- | --- | --- | --- | --- |
5353
| 1 | structs-and-classes | Done | Done | Done | Done |
54-
| 2 | constructors-and-invariants | Done | Planned | Planned | Planned |
54+
| 2 | constructors-and-invariants | Done | Done | Done | Done |
5555
| 3 | copy-and-move-semantics | Done | Planned | Planned | Planned |
5656
| 4 | inheritance-and-polymorphism | Done | Planned | Planned | Planned |
5757
| 5 | templates-basics | Done | Planned | Planned | Planned |

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ This repository teaches programming through small runnable examples and focused
2525
| Language | Current Levels | Module Coverage | Track Status |
2626
| --- | --- | --- | --- |
2727
| C++ | 00-setup, 01-foundations, 02-core, 03-advanced, 04-expert | Foundations, Core, Advanced, Expert, projects, assessments | Most complete and primary track |
28-
| C# | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 1/5 advanced modules | Advanced parity pilot in progress |
29-
| Go | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 1/5 advanced modules | Advanced parity pilot in progress |
30-
| Python | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 1/5 advanced modules | Advanced parity pilot in progress |
28+
| C# | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 2/5 advanced modules | Advanced parity in progress |
29+
| Go | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 2/5 advanced modules | Advanced parity in progress |
30+
| Python | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 2/5 advanced modules | Advanced parity in progress |
3131

3232
Parity planning reference: [LANGUAGE_PARITY_MATRIX.md](LANGUAGE_PARITY_MATRIX.md)
3333

languages/csharp/03-advanced/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ This level starts advanced object modeling and type design.
55
## Module Order
66

77
1. [structs-and-classes](./structs-and-classes/README.md)
8+
2. [constructors-and-invariants](./constructors-and-invariants/README.md)
89

910
Track progress in [../CHECKLIST.md](../CHECKLIST.md).
1011

1112
## Study Tip
1213

13-
Use `structs-and-classes` first to build clear mental models for value vs reference types before adding more advanced modules.
14+
Use `constructors-and-invariants` after `structs-and-classes` to enforce object rules consistently from construction to updates.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Constructors and Invariants (C#)
2+
3+
This module shows how constructors enforce valid object state.
4+
5+
## Quick Run
6+
7+
~~~bash
8+
dotnet run --project example/constructors-and-invariants-example.csproj
9+
~~~
10+
11+
## Topics Covered
12+
13+
- Constructor guards that normalize invalid inputs.
14+
- Defining invariants as always-true class rules.
15+
- Safe update methods that reject invalid transitions.
16+
- Reporting operation success without breaking object state.
17+
18+
## Common Pitfalls
19+
20+
- Accepting invalid constructor values and fixing later.
21+
- Updating private state directly from callers.
22+
- Returning success when an invalid update was ignored.
23+
24+
## Exercise Focus
25+
26+
- exercises/01.cs: bank account with non-negative balance invariant.
27+
- exercises/02.cs: date model with month/day validation.
28+
29+
### Exercise Specs
30+
31+
1. exercises/01.cs
32+
- Input: initial balance and transaction values.
33+
- Output: updated balance with validity checks.
34+
- Edge cases: negative initial balance; withdrawal beyond balance.
35+
36+
2. exercises/02.cs
37+
- Input: month and day values.
38+
- Output: valid/invalid date result.
39+
- Edge cases: month out of range; day out of range for month.
40+
41+
## Checkpoint
42+
43+
- [ ] I can define clear invariants for a class.
44+
- [ ] I can enforce invariants in constructors and methods.
45+
- [ ] I can reject invalid updates safely.
46+
- [ ] I completed exercises/01.cs.
47+
- [ ] I completed exercises/02.cs.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>disable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
</Project>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Example purpose: show the module flow with clear, beginner-friendly steps.
2+
3+
using System;
4+
5+
class Temperature
6+
{
7+
private double celsius;
8+
9+
public Temperature(double celsiusValue)
10+
{
11+
// Intent: enforce the invariant at construction time.
12+
celsius = celsiusValue < -273.15 ? -273.15 : celsiusValue;
13+
}
14+
15+
public bool SetCelsius(double newValue)
16+
{
17+
if (newValue < -273.15)
18+
{
19+
return false;
20+
}
21+
22+
celsius = newValue;
23+
return true;
24+
}
25+
26+
public double Celsius => celsius;
27+
}
28+
29+
class Program
30+
{
31+
static void Main()
32+
{
33+
// Program flow: construct with invalid input, then apply valid and invalid updates.
34+
Temperature temperature = new Temperature(-500.0);
35+
Console.WriteLine($"Initial value (clamped): {temperature.Celsius} C");
36+
37+
bool updated = temperature.SetCelsius(25.0);
38+
Console.WriteLine($"Set to 25.0 success: {updated}");
39+
Console.WriteLine($"Current value: {temperature.Celsius} C");
40+
41+
bool rejected = temperature.SetCelsius(-300.0);
42+
Console.WriteLine($"Set to -300.0 success: {rejected}");
43+
44+
// Intent: final state confirms that invariant was preserved.
45+
Console.WriteLine($"Current value: {temperature.Celsius} C");
46+
}
47+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
3+
class BankAccount
4+
{
5+
private double balance;
6+
7+
public BankAccount(double initialBalance)
8+
{
9+
balance = initialBalance < 0.0 ? 0.0 : initialBalance;
10+
}
11+
12+
public bool Deposit(double amount)
13+
{
14+
if (amount <= 0.0)
15+
{
16+
return false;
17+
}
18+
19+
balance += amount;
20+
return true;
21+
}
22+
23+
public bool Withdraw(double amount)
24+
{
25+
if (amount <= 0.0 || amount > balance)
26+
{
27+
return false;
28+
}
29+
30+
balance -= amount;
31+
return true;
32+
}
33+
34+
public double Balance => balance;
35+
}
36+
37+
class Program
38+
{
39+
static void Main()
40+
{
41+
Console.Write("Initial balance: ");
42+
if (!double.TryParse(Console.ReadLine(), out double initialBalance))
43+
{
44+
Console.WriteLine("Invalid initial balance.");
45+
return;
46+
}
47+
48+
BankAccount account = new BankAccount(initialBalance);
49+
50+
Console.Write("Deposit amount: ");
51+
if (double.TryParse(Console.ReadLine(), out double depositAmount))
52+
{
53+
account.Deposit(depositAmount);
54+
}
55+
56+
Console.Write("Withdraw amount: ");
57+
if (double.TryParse(Console.ReadLine(), out double withdrawAmount))
58+
{
59+
if (!account.Withdraw(withdrawAmount))
60+
{
61+
Console.WriteLine("Withdrawal rejected.");
62+
}
63+
}
64+
65+
Console.WriteLine($"Final balance: {account.Balance}");
66+
}
67+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
3+
class SimpleDate
4+
{
5+
private readonly int month;
6+
private readonly int day;
7+
8+
public SimpleDate(int monthValue, int dayValue)
9+
{
10+
month = monthValue;
11+
day = dayValue;
12+
}
13+
14+
public bool IsValid()
15+
{
16+
if (month < 1 || month > 12)
17+
{
18+
return false;
19+
}
20+
21+
int[] daysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
22+
return day >= 1 && day <= daysInMonth[month - 1];
23+
}
24+
}
25+
26+
class Program
27+
{
28+
static void Main()
29+
{
30+
Console.Write("Enter month and day: ");
31+
string raw = Console.ReadLine() ?? string.Empty;
32+
string[] parts = raw.Split(' ', StringSplitOptions.RemoveEmptyEntries);
33+
34+
if (parts.Length != 2 ||
35+
!int.TryParse(parts[0], out int month) ||
36+
!int.TryParse(parts[1], out int day))
37+
{
38+
Console.WriteLine("Invalid input.");
39+
return;
40+
}
41+
42+
SimpleDate date = new SimpleDate(month, day);
43+
Console.WriteLine(date.IsValid() ? "Valid date" : "Invalid date");
44+
}
45+
}

languages/csharp/CHECKLIST.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
## 03-advanced
2424

2525
- [ ] Complete `03-advanced/structs-and-classes`.
26+
- [ ] Complete `03-advanced/constructors-and-invariants`.
2627

2728
## Parity Goals
2829

languages/csharp/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This track currently covers `01-foundations`, `02-core`, and early `03-advanced`
66

77
- 8/8 foundations modules implemented.
88
- 6/6 core modules implemented (`input-validation`, `algorithms-basics`, `file-io-basics`, `sorting-and-searching`, `maps-and-frequency-counting`, `error-handling-and-defensive-programming`).
9-
- 1/5 advanced modules implemented (`structs-and-classes`).
9+
- 2/5 advanced modules implemented (`structs-and-classes`, `constructors-and-invariants`).
1010
- Same module naming as C++, Python, and Go for parity.
1111

1212
## Prerequisites
@@ -47,6 +47,7 @@ dotnet run --project 01-foundations/types-and-io/example/types-and-io-example.cs
4747
- [error-handling-and-defensive-programming](./02-core/error-handling-and-defensive-programming/README.md)
4848
- [03-advanced](./03-advanced/README.md)
4949
- [structs-and-classes](./03-advanced/structs-and-classes/README.md)
50+
- [constructors-and-invariants](./03-advanced/constructors-and-invariants/README.md)
5051

5152
## Progress Tracking
5253

0 commit comments

Comments
 (0)