Skip to content

Commit e08801a

Browse files
Adds example usage to the project README
1 parent 2e1a9ef commit e08801a

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,61 @@ What they should have seen on their receipt is either:
2323
`Special Product @ £3.08 x 300 = £924.00` or `Special Product @ £3.0771 x 300 = £923.13`
2424

2525
Of course, how this is handled should be a business decision 📈, but we should be able to guarantee the decision in our code. If we can leverage the type system to help us out, we can make this a compile-time requirement. `RoundedDecimal` can help us with that.
26+
27+
## Example usage
28+
29+
The way that `RoundedDecimal` works is that it forces you to think about how you would like to deal with handling numbers of varying decimal places. For example, dealing with an item price that has 2 decimal places, and an exchange rate that has 5 decimal places. Using a regular decimal you can simply do: `let localPrice: Decimal = itemPrice * exchangeRate` which may look like `2.59 * 1.12345` resulting in the value `2.9097355`. This number may go off to other parts of the system as described in the `Why` section above.
30+
31+
Using `RoundedDecimal`, the code has to be more explicit. For example, this code would **fail** to compile as we're trying to multiply two numbers of different precision:
32+
33+
```swift
34+
let listedUSDPrice: RoundedDecimal<Places.two> = "2.59"
35+
let exchangeRate: RoundedDecimal<Places.five> = "1.12345"
36+
37+
let localPrice = listedUSDPrice * exchangeRate
38+
```
39+
40+
The compilation failure look like:
41+
42+
```bash
43+
binary operator '*' cannot be applied to operands of type 'RoundedDecimal<Places.two>' and 'RoundedDecimal<Places.five>'
44+
let localPrice = listedUSDPrice * exchangeRate
45+
~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
46+
```
47+
48+
Instead, a decision would need to be made. Either we reduce the precision of the exchange rate to two decimal places to match that of the listed price:
49+
50+
```swift
51+
let listedUSDPrice: RoundedDecimal<Places.two> = "2.59"
52+
let exchangeRate: RoundedDecimal<Places.five> = "1.12345"
53+
54+
let shortExchangeRate: RoundedDecimal<Places.two> = exchangeRate.withInferredPrecision()
55+
let localPrice = listedUSDPrice * shortExchangeRate // localPrice would result in 2.90
56+
57+
```
58+
59+
Or, we increase the precision of the listed price to five decimal places so that we can keep the precision of the exchange rate in our calculation:
60+
61+
```swift
62+
63+
let listedUSDPrice: RoundedDecimal<Places.two> = "2.59"
64+
let exchangeRate: RoundedDecimal<Places.five> = "1.12345"
65+
66+
let longListedUSDPrice: RoundedDecimal<Places.five> = listedUSDPrice.withInferredPrecision()
67+
let localPrice = longListedUSDPrice * exchangeRate // localPrice would result in 2.90974
68+
```
69+
70+
Notice that each approach is explicit and results in different values. Its also worth noting that increasing the precision of the listed price doesn't actually change its value, it'll still be 2.59 but it allows it to be treated as a number with five decimal places, making it explicitly 2.59000.
71+
72+
### Converting precisions
73+
74+
As with the example shown above, when dealing with numbers of different precisions in an operation, we need to be explicit. To do this we use the Swift type system, generics and inference.
75+
76+
To explicitly change the precision of a number we must use `withInferredPrecision()` where the expression result is explicitly typed.
77+
78+
For example to convert a number with five decimal places to one which has two decimal places:
79+
80+
```swift
81+
let exchangeRate: RoundedDecimal<Places.five> = "1.12345"
82+
let shortExchangeRate: RoundedDecimal<Places.two> = exchangeRate.withInferredPrecision() // shortExchangeRate would result in 1.12
83+
```

0 commit comments

Comments
 (0)