Inheritance¶
didactic supports both single and multiple inheritance. The Theory derivation handles each in a different way:
- Single inheritance flattens the field set. The metaclass walks
the MRO when collecting field specs, so
class B(A)simply has every field fromAplus its own. - Multi inheritance triggers a panproto colimit (pushout) of the parent Theories over their lowest common ancestor.
Single inheritance¶
import didactic.api as dx
class A(dx.Model):
x: int
class B(A):
y: int
b = B(x=1, y=2)
b.x # 1
b.y # 2
B.__field_specs__ contains both x and y. B.__theory__ is the
flat Theory built from the merged spec; no colimit is involved.
Inherited axioms (__axioms__) are also collected: B is checked
against both its own and A's.
Multi inheritance¶
class Shared(dx.Model):
id: str
class Reads(Shared):
read_count: int = 0
class Writes(Shared):
write_count: int = 0
class Both(Reads, Writes):
note: str = ""
When Both's Theory is built, didactic walks Both's immediate
parents (Reads and Writes), finds their lowest common ancestor in
the Model lineage (Shared), and computes the colimit:
The result is the categorical pushout. panproto validates that the join is consistent (the shared sub-theory's sorts and operations appear with the same shape in both parents).
For three or more parents, the colimit is computed left-to-right.
The end result is the same panproto Theory you would get by listing
all the fields on Both directly, but going through colimit_theories
asserts that the parents' Theories are compatible at the categorical
level.
What goes wrong, and how¶
A multi-inheritance setup that produces an inconsistent join surfaces
as a panproto.GatError at first __theory__ access (which is
typically your first interesting use of the class). Common causes:
- Two parents declaring fields with the same name but different types. didactic catches this earlier as a Python-side metaclass error, but a panproto-side variant can still surface for richer shapes.
- Two parents with conflicting axioms. The colimit refuses to merge contradictory equations.
If you see a GatError, the message names the offending sort or
equation; the fix is usually to factor the conflict into a common
ancestor or to drop one branch.