1.3 TopKit: Presence - JulTob/Tag_Oriented_Programming GitHub Wiki

Presence: a gain at an Agent

"balance" @ agent reads “balance at agent”: does this Agent have that Contribution? The answer is a Boolean. The name is enough; its kind and origin do not belong in the question.

The examples below run in order as one program.

Presence is different from value

from TopKit import Action, Contract, Post, Record, Tag


class Host:
    pass


class Account(Tag):
    @Record
    def balance(agent):
        return None


account = Host()
account.owner = "Ari"                 # supplied by the Python host
Account(account)

assert "balance" @ account
assert "owner" @ account
assert not ("credit_limit" @ account)

for value in (None, False, 0, "", []):
    account.balance = value
    assert "balance" @ account

None, False, zero and empty values are present. A missing Contribution is absent. Deleting its binding makes the query false, even if a Tag once declared it.

The query does not call Actions or Operations, evaluate a Report or host property getter, or run Postconditions. A host property counts as a provided binding; presence does not promise that reading it will succeed. Host members participate too, but values invented only by a host's dynamic __getattr__ do not count. An unfilled host slot is absent.

Names survive changes of kind

class Calculated_Balance(Account):
    @Action
    def balance(agent):
        return 0


calculated = Host()
Account(calculated)
assert "balance" @ calculated        # a Record
Calculated_Balance(calculated)
assert "balance" @ calculated        # now an Action; it was not called

The query asks what the Agent has now. It does not assert which Tag supplied it, its kind, its value, or whether it is callable.

Require a Contribution with a Post

A Contribution can be optional. A Post makes its presence a promise:

class Balanced(Tag):
    @Post
    def Has_Balance(agent):
        assert "balance" @ agent


account.balance = None
Balanced(account)
assert Contract.Holds(account)

del account.balance
assert not Contract.Holds(account)
assert account in Balanced[:]        # the Tag remains; its promise is broken

account.balance = False
assert Contract.Holds(account)       # presence restored, even with False

Python removes assert statements under python -O. For a promise that must also be checked in optimized Python, return the Boolean explicitly. Short-circuit and checks presence before reading the value:

class Funded(Tag):
    @Post
    def Nonnegative_Balance(agent):
        return ("balance" @ agent
                and agent.balance is not None
                and agent.balance >= 0)


account.balance = 0
Funded(account)
assert Contract.Holds(account)


class Has_An_Owner(Tag):
    Identified = Post(lambda agent: "owner" @ agent)


Has_An_Owner(account)
assert Contract.Holds(account)

The named lambda is another spelling of a named Post. Its promise is Identified; lambda syntax adds no permanence or protection against replacement or deletion. A lambda cannot contain an assert statement.

Guard an Action when it needs the Contribution

class Balance_Reader(Tag):
    @Action
    def Read_Balance(agent):
        if not ("balance" @ agent):
            raise LookupError("Read_Balance requires balance")
        return agent.balance


reader = Host()
Balance_Reader(reader)
try:
    reader.Read_Balance()
except LookupError:
    pass
else:
    raise AssertionError("a missing balance must be reported")

reader.balance = None
assert reader.Read_Balance() is None

This checks availability at the point of use. Presence alone does not grant permission or prove that an Agent is sound. Express those requirements separately in the Action or its applicable contract.

Ask a Field: all, any, one, or a selection

class Crew(Tag):
    @Post
    def Alive(agent):
        return agent.alive


ari, bo, cal = Host(), Host(), Host()
for member in (ari, bo, cal):
    member.alive = True
    Crew(member)
ari.email = None
bo.email = "[email protected]"
cal.alive = False

assert not all("email" @ member for member in Crew[:])
assert all("email" @ member for member in Crew)
assert any("email" @ member for member in Crew[:])

first = next((member for member in Crew[:] if "email" @ member), None)
assert first is ari
selected = [member for member in Crew[:] if "email" @ member]
assert selected == [ari, bo]
assert list(filter(lambda member: "email" @ member, Crew[:])) == selected

missing = [member for member in Crew[:] if not ("email" @ member)]
assert missing == [cal]

Choose the population first: Crew[:] includes everyone in the Field; Crew selects sound Agents and therefore checks their contracts. The presence query itself does not check contracts. The same expressions work over combined populations such as Crew[:] | OtherRole[:].

Python's all is true for an empty population; any is false. next(..., None) returns the first match, or None when there is none. These are ordinary Python selections, preserving Field iteration order. A list records that selection at that moment.

The Agent now, or a Tag view's captured Overlay

saved = Account[calculated]
del calculated.balance
assert not ("balance" @ calculated)
assert "balance" @ saved

The Agent answers from its current bindings. A Tag-bound view answers from its captured Overlay. A positive view query does not guarantee the same name is still present on the live Agent.

Secrets follow the existing composition door: their names are absent outside it and visible inside it. Shared Reports and Operations follow their existing access rules: the Agent sees published names; a Tag view can inspect the shared names in its captured context. A remaining binding can still be unusable after Rip. Presence is not a promise that a later read or call will succeed.

Use this syntax on an existing TOP Agent or a Tag-bound view. Tagging installs it; an ordinary host before its first Tagging does not support it, including inside that first Tag's Precondition. String operands select presence; other operands retain the existing matrix-operator behavior.

Continue with Contracts for promises and repair, or Fields for population selection and set algebra.