Skip to content

CEP-0006: Runtime Type Identity and Dyn Casts

Draft

Draft proposal for runtime concrete type identity, downcasting, sidecasting, and richer dynamic contract conversion. V1 dynamic dispatch supports represented-surface upcasts only.

Summary

Catalyst should eventually decide whether dynamic contract objects and owned dynamic boxes carry enough public runtime identity to support downcasting, sidecasting, and dynamic conformance lookup.

V1 deliberately does not expose runtime concrete type identity. upcast and dynamic dependency upcasts select metadata already represented by the erased surface; they do not inspect the hidden concrete payload for unrelated conformances.

Example

Possible future shape:

fn try_use_debug(value: *dyn Display) {
  if const debug = value.cast_dyn(Debug) {
    debug.debug_print()
  }
}

fn recover_widget(value: Box(dyn Display)) ?Box(Widget) {
  return value.downcast(Widget)
}

Both operations require runtime identity that V1 dynamic values deliberately do not expose.

Motivation

Owned and borrowed dynamic values are useful without downcasting, but some systems eventually need controlled recovery:

  • Box(dyn A) to concrete Box(T) when the hidden payload is known to be T;
  • Box(dyn A) to Box(dyn B) when the hidden concrete type implements B;
  • borrowed *dyn A tests against concrete or unrelated dynamic surfaces;
  • diagnostics and tooling that can explain erased values without exposing unstable layout details.

These operations require runtime identity, visibility, module-stability, and ABI decisions that are larger than V1 dyn dispatch.

Proposed Direction

The future design should distinguish:

  • upcasts along already represented contract dependencies;
  • same-surface normalization and intersection subset selection;
  • concrete downcasts;
  • sidecasts through hidden concrete conformance lookup;
  • owner-preserving conversions such as Box(dyn A) to Box(dyn B);
  • borrowed pointer conversions such as *dyn A to ?*dyn B or an equivalent fallible result.

Downcasts and sidecasts should be explicit and fallible unless the source type already proves the target. They must not allocate merely to answer a type test or borrowed conversion.

Metadata Boundary

Runtime identity should not require storing comptime reflection objects at runtime. V1 already separates comptime Type.DynMetadata from runtime-storable descriptor fields. Any future identity token should be a runtime-storable descriptor with clear stability, equality, and visibility rules.

Open Questions

  • Is type identity stable across module versions, dynamic linking, or separate compilation?
  • Does sidecasting require target conformance visibility at the cast site, at original erasure, or both?
  • What result type does a failed cast use?
  • Can dynamic boxes recover concrete ownership without moving payload bytes?
  • How does this interact with C ABI layout promises, if any?

V1 Compatibility

V1 remains allocation-free for represented-surface upcasts and does not promise public dyn layout. Active docs should describe V1 upcast behavior locally and reference this CEP for downcasting, sidecasting, and runtime identity.