1683. gopy abstract
What we are porting
Objects/abstract.c (~3000 lines). The dispatcher layer between
the VM and the type slots. Every BINARY_OP, COMPARE_OP, GET_ITER,
FOR_ITER opcode (and their kin) routes through here.
Five families:
PyObject_*: Length, GetItem, SetItem, DelItem, GetAttr, SetAttr, RichCompare, Hash, Type, IsInstance, IsSubclass, Repr, Str, Bytes, Format, Call, Iter.PyNumber_*: Add, Subtract, Multiply, MatMul, TrueDivide, FloorDivide, Remainder, Divmod, Power, Negative, Positive, Absolute, Invert, Lshift, Rshift, And, Or, Xor, Index, AsSsizeT, ToBase, plus the in-place variants.PySequence_*: Length, Concat, Repeat, GetItem (int index), SetItem, GetSlice, SetSlice, Tuple, List, Fast, Count, Contains, Index, InPlaceConcat, InPlaceRepeat.PyMapping_*: Length, GetItem (key), SetItem, HasKey, Keys, Values, Items.PyIter_*: Check, Next, Send.
Why this exists
Each family is a thin wrapper around the type slots, with
fallback rules. PyNumber_Add tries nb_add on the left operand,
then the reflected slot on the right operand if the left returns
NotImplemented or doesn't implement it, with the subclass-priority
rule. PySequence_GetItem normalises negative indices. PyObject_Hash
checks tp_hash and raises TypeError if NULL.
The fallback rules are observable through normal Python code, so the dispatcher matters for behavioural compatibility.
Go shape
package objects
// Add is PyNumber_Add. Tries left.nb_add, falls through to
// right.nb_add (reflected) per the subclass-priority rule.
func Add(a, b Object) (Object, error)
// GetItem is PyObject_GetItem. Routes to mp_subscript first,
// falls through to sq_item with index conversion.
func GetItem(o, key Object) (Object, error)
// Iter is PyObject_GetIter. Returns o.tp_iter() if defined,
// or a sequence-fallback iter if sq_item is defined.
func Iter(o Object) (Object, error)
// IterNext is PyIter_Next. Returns (nil, ErrStopIteration) at end.
func IterNext(it Object) (Object, error)
Errors flow through Go return values; the C NULL-with-exception
convention becomes a typed error.
Subclass priority
Critical rule: if the right operand's type is a strict subclass of
the left operand's type, the right's reflected slot runs first.
This is how Fraction(1, 2) + 1 returns a Fraction rather than
falling through to int.__add__.
File mapping
| C source | Go target |
|---|---|
Objects/abstract.c PyObject_* | objects/abstract_object.go |
Objects/abstract.c PyNumber_* | objects/abstract_number.go |
Objects/abstract.c PySequence_* | objects/abstract_sequence.go |
Objects/abstract.c PyMapping_* | objects/abstract_mapping.go |
Objects/abstract.c PyIter_* | objects/abstract_iter.go |
Checklist
Status legend: [x] shipped, [ ] pending, [~] partial / scaffold,
[n] deferred / not in scope this phase.
Files
- [~]
objects/abstract_object.go: Length, GetItem, SetItem, DelItem, RichCompare, Hash, Repr, Str. v0.2 subset shipped. - [~]
objects/abstract_number.go: Add, Subtract, Multiply, TrueDivide, FloorDivide, Remainder, Power, Negative, Positive, Absolute, Bool. Subclass-priority rule for binops. v0.2 subset shipped. -
objects/abstract_number.go(full): Lshift, Rshift, And, Or, Xor, Invert, MatMul, Index, AsSsizeT, ToBase, plus all in-place variants. - [~]
objects/abstract_sequence.go: Length, GetItem, SetItem, Tuple, List, Contains, Iter, Concat. v0.2 subset shipped. -
objects/abstract_sequence.go(full): GetSlice, SetSlice, Count, Index, Repeat, Fast, InPlaceConcat, InPlaceRepeat. -
objects/abstract_mapping.go: Length, GetItem, SetItem, HasKey, Keys, Values, Items. - [~]
objects/abstract_iter.go: Iter, IterNext. v0.2 shipped. -
objects/abstract_iter.go(full): Check, Send, GetAIter, ANext. -
objects/abstract_test.go: subclass-priority panel, reflected-slot fallback, NotImplemented handling.
Surface guarantees
- Subclass priority: when
type(b)is a strict subclass oftype(a),a + bcallsb.__radd__first. - NotImplemented from both sides raises TypeError with the CPython text ("unsupported operand type(s) for +: 'X' and 'Y'").
- PyNumber_Index follows the
__index__chain; reject bool-from-int special-cased path is preserved. - PyIter_Next on a non-iterator raises TypeError with the CPython text.
- PySequence_Contains routes through
__contains__if defined, falls back to iteration. - PyObject_Hash raises TypeError on unhashable types with the CPython text including the type name.
Cross-references
- Type slots: 1672.
- Per-type implementations: 1673-1689.
Out of scope
tp_async_*async-iter slots beyond the v0.2 subset. Lands alongside generators (1687) in v0.6.