Those tests are a bit difficult to grasp. Especially because they start with unary operations. I think it would be better if you started with binary operations:
func test_add_toCopy_doesNotModifyOriginal() {
// int + int
var value = BigInt(Int.max)
var copy = value
_ = copy + self.int
XCTAssertEqual(value, BigInt(Int.max))
}
func test_addEqual_toCopy_doesNotModifyOriginal() {
// int + int
var value = BigInt(Int.max)
var copy = value
copy += self.int
XCTAssertEqual(value, BigInt(Int.max))
}
The general idea is that the original value should not be modified when we perform operation on copy. It will not test if the copy was created before (var copy = value) or during the write (actual COW), but it will test that the copy was made at some point.
The general idea is that BigInt will probably allocate on the heap. What happens when we modify the heap value? All of them change? Or maybe only the BigInt that was used in operation? It is easy to break the invariant if you implement COW by hand.
Alternatively you could make BigInt non-copyable (move-only). Then you chose:
1) copy heap on BigInt copy (no COW)
reference count, so that BigInt is a struct with explicit copy/retain (COW, acting like a smart pointer, RAII etc.)
Obviously move-only is extremely un-ergonomic, so…
Please read the #242 Using tests from “Violet - Python VM written in Swift” before.
All pass.
🐰 Discussion
Those tests are a bit difficult to grasp. Especially because they start with unary operations. I think it would be better if you started with binary operations:
The general idea is that the original
value
should not be modified when we perform operation oncopy
. It will not test if the copy was created before (var copy = value
) or during the write (actualCOW
), but it will test that the copy was made at some point.The general idea is that
BigInt
will probably allocate on the heap. What happens when we modify the heap value? All of them change? Or maybe only theBigInt
that was used in operation? It is easy to break the invariant if you implement COW by hand.Alternatively you could make
BigInt
non-copyable (move-only). Then you chose: 1) copy heap onBigInt
copy (no COW)BigInt
is astruct
with explicitcopy/retain
(COW, acting like a smart pointer, RAII etc.)Obviously move-only is extremely un-ergonomic, so…