You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add implementation lessons learned to teaching notes
Document practical issues encountered during Record type implementation:
- Hash constants not publicly exposed (copy from tupleobject.c)
- GC trashcan macros for deep recursion protection
- PyUnicode_Compare error handling
- Opcode number selection (166 after DICT_UPDATE)
- Python-level constructor (tp_new) for testing
- Type initialization order in object.c and bltinmodule.c
- Correct allocator (PyObject_GC_NewVar)
- tp_basicsize calculation for flexible array members
Also added testing checklist for verifying implementation.
Use this as reference when student gets stuck, but guide them to discover solutions themselves first.
358
+
359
+
---
360
+
361
+
## Lessons Learned During Implementation
362
+
363
+
These are practical issues encountered during actual implementation:
364
+
365
+
### 1. Hash Constants Not Publicly Exposed
366
+
367
+
The XXH3-style hash constants (`_PyHASH_XXPRIME_1`, `_PyHASH_XXPRIME_2`, `_PyHASH_XXPRIME_5`) used by `tupleobject.c` are defined locally in that file, not in a header. Had to copy them into `recordobject.c`:
**Teaching point:** Internal implementation details are often not exposed. Look at how existing code solves the same problem.
384
+
385
+
### 2. GC Trashcan for Deep Recursion
386
+
387
+
Deallocation needs `Py_TRASHCAN_BEGIN`/`Py_TRASHCAN_END` to prevent stack overflow when destroying deeply nested structures:
388
+
389
+
```c
390
+
staticvoid
391
+
record_dealloc(RecordObject *r)
392
+
{
393
+
PyObject_GC_UnTrack(r);
394
+
Py_TRASHCAN_BEGIN(r, record_dealloc)
395
+
396
+
// ... cleanup code ...
397
+
398
+
Py_TRASHCAN_END
399
+
}
400
+
```
401
+
402
+
**Teaching point:** Check how `tuple_dealloc` and `list_dealloc` handle this.
403
+
404
+
### 3. PyUnicode_Compare Error Handling
405
+
406
+
`PyUnicode_Compare` can raise exceptions (e.g., if comparison fails). Must check `PyErr_Occurred()`:
407
+
408
+
```c
409
+
int cmp = PyUnicode_Compare(name, field);
410
+
if (cmp == 0) {
411
+
// found match
412
+
}
413
+
if (PyErr_Occurred()) {
414
+
return NULL;
415
+
}
416
+
```
417
+
418
+
### 4. Opcode Number Selection
419
+
420
+
Originally planned opcode 35, but ended up using 166 (right after `DICT_UPDATE` at 165). The gaps in the opcode table exist for historical reasons and some are reserved.
421
+
422
+
**Teaching point:** Look at recent additions to see where new opcodes go. `Lib/opcode.py` is the source of truth.
423
+
424
+
### 5. Python-Level Constructor (tp_new)
425
+
426
+
To test the Record type without emitting bytecode, need a Python constructor:
0 commit comments