Repository navigation
1.0.2 Layers and the Overlay
Each Tag contributes a Layer. The Overlay is what the Agent presents.
An Agent can carry several Tags at once. Each contributes its own meaning, Records and Actions to the same object.
In the previous example, Elf gave Ari a Languages Record and an Attack Action. What happens when another Tag also provides an Action called Attack?
TOP resolves contributions independently. The most recently applied contribution with that name becomes visible. Other contributions remain available.
Continuing with Ari from the previous page:
class Fighter(Tag):
# Another Attack Action
@Action
def Attack(agent):
return f"{agent.name} cuts with a blade."
Fighter(ari)
# This will raise a warning informing us of the conflict of names.
# It will solve towards the latest name declared.
assert ari.Attack() == "Ari cuts with a blade."
assert ari.Languages == "Elven, Sylvan, Common"Fighter contributes a new Attack, so ari.Attack() now selects that version. It contributes no Languages Record, so Ari keeps the one provided by Elf.
Ari still carries both Tags:
assert ari in Elf
assert ari in Fighter---
title: Ari
---
swimlane-beta TD
subgraph Fighter
fighter_attack("Attack")
end
subgraph Elf
elf_attack("Attack")
languages["Languages"] --- lng[\"Elven, <br> Sylvan, <br>Common"\]
end
subgraph Character
name["name: Ari"]
level["level: 3"]
end
fighter_attack <===x elf_attack
fighter_attack <-.-o name
elf_attack <-.-o name
Calling
ari.Attack()runs Fighter’s Action now. The thick connection represents overlaying; it does not mean that Fighter automatically calls Elf’s Action as well. The x next to elf's attack shows it was overwritten.
Note: TopKit warns when an Action replaces one from an independent Tag without an Underlay. The replacement is allowed. Extending the previous Action through an Underlay is a separate composition choice.
The Overlay may draw different names from different layers. Here:
-
ari.Attackresolves to the Action provided by Fighter. -
ari.Languagesholds the Record contributed by Elf. -
ari.nameandari.levelremain attributes supplied by Character.
Applying a Tag therefore does not replace the Agent’s entire interface. It contributes to the composition, changing the names it provides.
Sometimes we want to use the composition established by an earlier Tag.
Elf[ari] is an Agent-bound Tag view: it selects the Overlay established immediately after Elf’s current application to Ari. Adding Fighter does not redirect that view’s Attack.
# Ari's current Overlay:
assert ari.Attack() == "Ari cuts with a blade."
# The composition established after Elf:
assert Elf[ari].Attack() == "Ari attacks with elven grace."Both calls concern the same Ari. The access path determines which composition supplies the Action.
A view includes the earlier contributions available when that Tag was applied, including contributions from the host Class. It is more than a collection of methods declared inside the Tag.
The view is read-only and does not create a copy of Ari. Its guarantee concerns which layers it selects; it does not freeze all underlying data.
To check whether the current overlay provides a named contribution, you can check for the name using @:
assert "Attack" @ ari
assert "Languages" @ ariThese expressions ask whether the names are present. They do not call Attack or test the value held in Languages.