Weekly Review — Month 1 · Week 4 (Days 022–028)¶
📅 The Week in One Line¶
Composed types with embedding, generalized algorithms with generics and generic containers, and tied it all together in a tested, zero-dependency CLI (taskcli) — closing out Month 1.
✅ What I Completed¶
- Day 022 — Struct embedding & composition (promotion, shadowing, interface embedding)
- Day 023 — Generics fundamentals (type params,
any/comparable/cmp.Ordered/unions, inference) - Day 024 — Generic data structures:
Stack[T]&Set[T] - Day 025 — Project:
Taskmodel + atomic JSON store - Day 026 — Project: subcommands & flags via stdlib
flag - Day 027 — Project: table-driven tests (
t.TempDir) + README - Day 028 — Week 4 + Month 1 review; tag
v0.1.0 - Runnable examples:
embedding,generics,generic-ds,cli-flags - Exercises solved: 3 (genslice, genstack, genset) — all table-driven, green
💡 Lessons Learned¶
- Embedding is composition, not inheritance: members are promoted (auto-forwarded), but there's no subtyping and no virtual dispatch. The outer type shadows promoted members of the same name.
- Pick the weakest constraint that compiles:
anyfor a pure container,comparablefor map-keyed sets,cmp.Orderedonly when you compare with</>. Unions need~to accept named types. - Generics shine when the algorithm is identical across types; switch to an interface when behavior differs by type. They're complements, not competitors.
- Generic "empty" returns must use
var zero T— you can't writenil/0for an arbitraryT. - Treat a missing data file as an empty store, not an error (
errors.Is(err, os.ErrNotExist)); save atomically with temp-file +os.Renameso a crash never corrupts data. - Keep
maina one-liner overrun([]string) error: testable, andos.Exit(which skips defers) stays at the top level only. t.TempDir()+ table-driven subtests make file-backed code easy to test with zero cleanup; assert error paths witherrors.Is, never string compares.
💪 Strengths (what clicked)¶
- Reading and writing generic signatures, and choosing generics vs interfaces deliberately.
- Building small, well-tested containers; the
flagsubcommand pattern.
🧩 Weaknesses (what's still fuzzy)¶
- Reflex to choose
cmp.Orderedvscomparableunder time pressure. - Remembering
~in union constraints for named types. - Method-set subtleties when embedding pointer vs value types.
🔁 Spaced-Repetition Re-quiz (topics from earlier weeks)¶
- Q: (Wk2) Why can
appendmutate a slice you passed in, and how do you avoid it?A
Slices share a backing array; ifappendhas spare cap it writes in place, aliasing the caller's data. Copy first (append([]T(nil), s...)) or full-slices[a:b:b]to force a new array. - Q: (Wk3) A function returns
error; a typed nil*MyErris assigned to it. Is the result== nil?A
No — the interface holds a non-nil type with a nil value, so it's non-nil. Return literalnilfor success. - Q: (Wk1) What does
iotaequal on the third ConstSpec line of aconstblock?A
2 — it starts at 0 and increments by one per line in the block. - Q: (Wk3) Which is in the method set of
T(value): value-receiver methods, pointer-receiver methods, or both?A
Only value-receiver methods.*T's method set includes both. An addressableTcan still call pointer methods via auto-&, but the method set ofTitself excludes them.
🎯 Action Items¶
- Add a one-page "generics vs interfaces" decision note to the cheatsheets.
- Drill the
comparablevscmp.Ordereddistinction in flashcards. - Re-implement
Stack[T]/Set[T]from scratch, closed-book, once next week. - Replace hand-rolled helpers with
slices/mapsstdlib in a refactor pass.
🚀 Next Week Goals¶
- Begin Month 2 (Concurrency & the runtime): goroutines, channels,
select,syncprimitives, andcontext. - Carry the
run() error+ table-driven testing discipline into concurrent code (add-race). - Extend
taskcliideas toward a concurrent/server variant later in the month.
📊 Metrics¶
| Hours | Days hit | Exercises | Commits | Avg confidence |
|---|---|---|---|---|
| 10 | 7/7 | 3 | 9 | 3.⅘ |
Suggested commit: docs(journal): week 4 review