191 lines
6.8 KiB
Markdown
191 lines
6.8 KiB
Markdown
# 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.
|