prometeu-studio/docs/pbs/decisions/Value Representation and Identity Decision.md

6.8 KiB

Value Representation and Identity Decision

Status: Accepted (Implemented) Cycle: Initial value-representation closure pass

1. Context

PBS v1 needs a stable user-visible model for:

  • which values are pure copied payloads,
  • which values preserve shared runtime identity,
  • which carriers merely wrap other values,
  • and how callback values fit into the language without exposing general first-class functions or closures.

Earlier decisions already fixed important inputs:

  • structs are reference-like in ordinary use,
  • services are canonical singleton values,
  • bind(context, fn_name) captures the same struct identity without copying it,
  • optional and result remain explicit carriers rather than implicit effect-lifting mechanisms.

2. Decision

PBS v1 adopts the following value-representation baseline:

  1. Pure scalar-like values are copied by value and do not carry user-visible identity.
  2. Struct values are identity-bearing, heap-backed reference values.
  3. Service values are identity-bearing canonical singleton values.
  4. Host-backed resource values are identity-bearing values on the PBS side, even though their backing authority remains host-owned.
  5. Tuple, optional, and result carriers do not introduce identity of their own.
  6. Contract values do not introduce a new user-visible identity distinct from the underlying struct or service value.
  7. Callback values are first-class callable values in PBS v1, but callback identity is not promoted as a user-visible identity concept.
  8. Assignment, parameter passing, and return preserve aliasing for identity-bearing values and copy payload for pure value kinds.

3. Value Categories

3.1 Pure copied values

The following value kinds are pure copied values in the user model:

  • int
  • float
  • bool
  • enum values
  • canonical str

Assignment, parameter passing, and return of these values copy the value itself.

3.2 Identity-bearing values

The following value kinds carry stable user-visible identity:

  • struct values
  • service values
  • host-backed resource/handle values

Assignment, parameter passing, and return of these values preserve aliasing to the same runtime entity rather than copying an independent underlying object.

3.3 Carrier-only values

The following value kinds are carriers and do not create identity of their own:

  • tuples
  • optional
  • result

They preserve the semantics of the values they contain.

If a carrier contains an identity-bearing payload, the carrier transports that same payload identity rather than inventing a new one.

4. Structs

Struct values are always reference-like in PBS v1.

Rules:

  • new Struct(...) produces a fresh struct identity.
  • Assignment of a struct value copies the reference, not the underlying field storage.
  • Passing or returning a struct value preserves aliasing to the same struct instance.
  • Mutation through one alias is observable through other aliases to that same struct instance.

5. Services

Service values are canonical module-owned singleton values.

Rules:

  • A service value denotes the same singleton identity wherever it is used in the same resolved program.
  • Assignment, parameter passing, and return preserve that same singleton identity.
  • Service use does not create fresh service instances.

6. Contract Values

Contract values do not introduce a new user-visible entity.

A contract value is a runtime view over:

  • an underlying struct identity or service singleton identity,
  • together with the selected contract implementation used for dispatch.

For user-facing semantics:

  • aliasing is defined by the underlying struct or service value,
  • not by treating the contract wrapper as a separate identity-bearing object.

7. Callback Values

Callback values are first-class callable values in PBS v1.

This means they may be:

  • assigned to variables,
  • passed as arguments,
  • and returned from functions.

However, PBS v1 does not promote callback identity as an explicit user-visible identity concept.

7.1 Plain callback values

When a callback value is formed from a compatible top-level fn, it denotes a callable value over that target function.

7.2 Bound callback values

When a callback value is formed through bind(context, fn_name):

  • the same struct context identity is captured,
  • the context is not copied,
  • the callback retains the target function together with that captured context,
  • and invoking the callback behaves as if the target function is called with the captured context as its first argument.

7.3 User model

The language must explain callback behavior without requiring the user to reason about callback identity as if callbacks were ordinary heap objects.

It is sufficient to state that:

  • callbacks are first-class callable values,
  • bound callbacks retain their captured context,
  • and copies of a callback value preserve the same callable meaning and retained context.

8. Copy Versus Aliasing Rule

The general rule for PBS v1 is:

  • pure value kinds are copied by value,
  • identity-bearing kinds preserve aliasing,
  • carrier kinds preserve the semantics of their contained values and do not create identity of their own.

Examples:

  • assigning an int copies the integer value,
  • assigning a Struct value copies the reference to the same struct instance,
  • assigning an optional<Player> that contains some(player) preserves the same Player identity inside the carrier,
  • assigning a result<E> Player success payload preserves the same Player identity inside the carrier.

9. Beginner-Facing Model

The user-facing explanation should be:

  • some values are plain data, so passing them passes the value,
  • structs and services are shared entities, so passing them passes access to the same entity,
  • tuples, optional, and result only package values and do not become new entities by themselves,
  • callbacks are callable values, and bound callbacks keep the same captured context rather than copying it.

This wording is simple enough for beginners while still preserving the performance-relevant truth about aliasing and mutation.

10. Explicit Non-Decisions

This decision record does not yet close:

  • the exact runtime layout of any heap object,
  • collection value categories in detail,
  • the final host-backed handle representation syntax,
  • the final diagnostics wording for aliasing/copy visibility.

11. Spec Impact

This decision should feed at least:

  • docs/pbs/specs/10. Memory and Lifetime Specification.md
  • docs/pbs/specs/4. Static Semantics Specification.md
  • docs/pbs/specs/12. Diagnostics Specification.md

12. Validation Notes

The intended split is:

  • structs, services, and host-backed resources behave like identity-bearing entities,
  • tuples, optional, and result are carriers,
  • callbacks are first-class callable values without promoted callback identity in the user model.