Skip to content

Commit 22ddb1f

Browse files
rstacpooleclaude
andcommitted
Update README for new naming and document collision risk
- Update the Custom Units / Custom Dimensions examples to the new lowerCamelCase dimension properties (.length, .amount) so the docs don't demonstrate the now-deprecated PascalCase names. - Spell out in the Custom Dimensions section that a Quantity is identified solely by its raw string across all linked modules, so two modules using the same raw value silently collapse into one dimension. Recommend prefixing custom raw values (e.g. "Acme.Money") to avoid collisions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 9e0ce79 commit 22ddb1f

1 file changed

Lines changed: 16 additions & 8 deletions

File tree

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ let registryBuilder = RegistryBuilder()
128128
registryBuilder.addUnit(
129129
name: "centifoot",
130130
symbol: "cft",
131-
dimension: [.Length: 1],
131+
dimension: [.length: 1],
132132
coefficient: 0.003048 // This is the conversion to meters
133133
)
134134
let registry = registryBuilder.registry()
@@ -159,13 +159,13 @@ let registryBuilder = RegistryBuilder()
159159
try registryBuilder.addUnit(
160160
name: "apple",
161161
symbol: "apple",
162-
dimension: [.Amount: 1],
162+
dimension: [.amount: 1],
163163
coefficient: 1
164164
)
165165
try registryBuilder.addUnit(
166166
name: "carton",
167167
symbol: "carton",
168-
dimension: [.Amount: 1],
168+
dimension: [.amount: 1],
169169
coefficient: 48
170170
)
171171
let registry = registryBuilder.registry()
@@ -183,7 +183,7 @@ We can extend this example to determine how many cartons a group of people can p
183183
try registryBuilder.addUnit(
184184
name: "person",
185185
symbol: "person",
186-
dimension: [.Amount: 1],
186+
dimension: [.amount: 1],
187187
coefficient: 1
188188
)
189189
let person = try Unit(fromSymbol: "person", registry: registryBuilder.registry())
@@ -196,14 +196,14 @@ print(weeklyCartons) // Prints '350.0 carton/week'
196196

197197
### Custom Dimensions
198198

199-
The built-in `Quantity` dimensions (`Length`, `Mass`, `Time`, etc.) cover the ISQ base
199+
The built-in `Quantity` dimensions (`.length`, `.mass`, `.time`, etc.) cover the ISQ base
200200
quantities, but you can define your own dimension when none of them fit — for example, a
201201
`Money` dimension for cost calculations. Because `Quantity` is `RawRepresentable`, you can
202202
add one with a static extension:
203203

204204
```swift
205205
extension Quantity {
206-
static let money = Quantity(rawValue: "Money")
206+
static let money = Quantity(rawValue: "Acme.Money")
207207
}
208208
```
209209

@@ -223,8 +223,16 @@ let volume = Measurement(value: 24, unit: .meter.pow(3)) // 24 m^3
223223
print(rate * volume) // Prints '4320.0 $'
224224
```
225225

226-
Unlike repurposing an unrelated base quantity such as `Amount`, a dedicated dimension can't
227-
silently cancel against unrelated units. Use a unique `rawValue` for each distinct dimension.
226+
A dedicated dimension is safer than repurposing an unrelated base quantity such as `.amount`,
227+
which would silently cancel against unrelated units that share it. But the `rawValue` namespace
228+
is **global**: a `Quantity` is identified solely by its raw string, across every module linked
229+
into the program. If two modules each define a dimension with the same raw value — say both use
230+
`"Money"` — they are treated as *the same dimension* and will silently cancel against each other,
231+
producing wrong results with no error. There is no central registry to detect the clash.
232+
233+
To avoid this, namespace every custom `rawValue` with a prefix unique to your module or
234+
organization (e.g. `"Acme.Money"`, not `"Money"`), exactly as the example above does. Reserve
235+
bare names like `"Money"` for nothing, since you cannot know what another dependency has chosen.
228236

229237
## CLI
230238

0 commit comments

Comments
 (0)