Repository navigation
Story: Preserve immutable types under explicit names and shared contracts #39
Description
Preserve immutable types under explicit names and shared contracts
As a developer using spatial-types,
I want to identify immutable spatial values explicitly while sharing contracts with mutable values,
so that consumers can select the appropriate representation without confusing their guarantees.
Context
Parent Epic: #38.
Existing classes must retain their immutable behavior after renaming. This establishes the public foundation for the remaining Stories.
This is the first implementation Story of #38: rename the existing immutable types before adding mutable concrete classes. The library has never been used in production; no deprecated aliases or compatibility layer are required.
Approved contract: immutable aggregates reject mutable components rather than converting them implicitly.
Acceptance Criteria
- Every existing concrete spatial type is renamed with the Immutable suffix in its existing dimension and Geometry/Geography namespace; former class names are removed without aliases or deprecation.
- All concrete immutable spatial classes are final; shared abstract bases do not expose public mutation or copy-with-replacement operations to the wrong variant.
- Common spatial/type interfaces expose read operations only. ImmutableSpatialInterface and the applicable ImmutableInterface contracts expose with… operations exclusively for immutable objects.
- MutableSpatialInterface and applicable MutableInterface contracts extend the common read contracts and carry only the mutation operations relevant to mutable objects; detailed type-specific setters are implemented in the following Stories. No mutable class extends a concrete immutable class.
- Existing immutable constructor, accessor and with… behaviors are preserved, including partially null ordinates from Story: Allow partially null point ordinates #36.
- with… operations return a distinct instance without changing the receiver or indirectly changing an immutable source.
- Immutable aggregate constructors and replacement methods reject mutable spatial components, including nested mutable components, without implicit conversion and without changing the source aggregate or supplied objects.
- Spatial component contracts and getters of immutable aggregates expose immutable components; coordinate-array input remains supported and creates immutable descendants.
- Neither variant exposes a dimension setter. MutableSpatialInterface carries declared-SRID/reference and spatial-mode (family) setters; these change metadata without recalculating ordinates. Immutable equivalents remain with… operations.
- Coordinates and SpatialReference remain immutable auxiliary values without requiring an Immutable suffix.
Constraints
- Coordinate layout and spatial type remain fixed. Geometric validity is delegated to explicit spatial-validator use; do not introduce automatic validation, repair, reprojection or dimension conversion. Changes to declared family or reference preserve coordinates. Preserve the representable states established by Story: Allow partially null point ordinates #36.
- Follow the naming and namespace layout defined by Epic: Support mutable and immutable spatial objects #38. Preserve the distinction between technical representation and normative geometric validity under ISO/IEC 13249-3 and applicable OGC specifications.
Definition of Done
The project's common Definition of Done applies.
-
composer test-localpasses. -
composer qualitypasses. - Tests verify final immutable classes, read/immutable/mutable interface separation and rejection of mutable components, using a test double if concrete mutable types are not yet available.
- Regression tests cover unchanged immutable behavior and partially null ordinates after renaming; factories, tests and repository documentation use the renamed immutable classes.
- Story-specific public API documentation is updated.
Activity
feat(types)!: name immutable variants and separate shared contracts