aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md33
1 files changed, 16 insertions, 17 deletions
diff --git a/README.md b/README.md
index 6330f79..07e9952 100644
--- a/README.md
+++ b/README.md
@@ -12,10 +12,9 @@ composition will either deadlock or release the lock between functions (making
it non-atomic).
The `stm` API tries to mimic that of Haskell's [`Control.Concurrent.STM`](https://hackage.haskell.org/package/stm-2.4.4.1/docs/Control-Concurrent-STM.html), but
-this is not entirely possible due to Go's type system; we are forced to use
-`interface{}` and type assertions. Furthermore, Haskell can enforce at compile
-time that STM variables are not modified outside the STM monad. This is not
-possible in Go, so be especially careful when using pointers in your STM code.
+Haskell can enforce at compile time that STM variables are not modified outside
+the STM monad. This is not possible in Go, so be especially careful when using
+pointers in your STM code. Remember: modifying a pointer is a side effect!
Unlike Haskell, data in Go is not immutable by default, which means you have
to be careful when using STM to manage pointers. If two goroutines have access
@@ -31,22 +30,22 @@ applications in Go. If you find this package useful, please tell us about it!
See the package examples in the Go package docs for examples of common operations.
-See [example_santa_test.go](example_santa_test.go) for a more complex example.
+See [cmd/santa-example/main.go](cmd/santa-example/main.go) for a more complex example.
## Pointers
-Note that `Operation` now returns a value of type `interface{}`, which isn't included in the
+Note that `Operation` now returns a value of type `any`, which isn't included in the
examples throughout the documentation yet. See the type signatures for `Atomically` and `Operation`.
Be very careful when managing pointers inside transactions! (This includes
slices, maps, channels, and captured variables.) Here's why:
```go
-p := stm.NewVar([]byte{1,2,3})
+p := stm.NewVar[[]byte]([]byte{1,2,3})
stm.Atomically(func(tx *stm.Tx) {
- b := tx.Get(p).([]byte)
+ b := p.Get(tx)
b[0] = 7
- tx.Set(p, b)
+ stm.p.Set(tx, b)
})
```
@@ -57,11 +56,11 @@ Following this advice, we can rewrite the transaction to perform a copy:
```go
stm.Atomically(func(tx *stm.Tx) {
- b := tx.Get(p).([]byte)
+ b := p.Get(tx)
c := make([]byte, len(b))
copy(c, b)
c[0] = 7
- tx.Set(p, c)
+ p.Set(tx, c)
})
```
@@ -73,11 +72,11 @@ In the same vein, it would be a mistake to do this:
type foo struct {
i int
}
-p := stm.NewVar(&foo{i: 2})
+p := stm.NewVar[*foo](&foo{i: 2})
stm.Atomically(func(tx *stm.Tx) {
- f := tx.Get(p).(*foo)
+ f := p.Get(tx)
f.i = 7
- tx.Set(p, f)
+ stm.p.Set(tx, f)
})
```
@@ -88,11 +87,11 @@ the correct approach is to move the `Var` inside the struct:
type foo struct {
i *stm.Var
}
-f := foo{i: stm.NewVar(2)}
+f := foo{i: stm.NewVar[int](2)}
stm.Atomically(func(tx *stm.Tx) {
- i := tx.Get(f.i).(int)
+ i := f.i.Get(tx)
i = 7
- tx.Set(f.i, i)
+ f.i.Set(tx, i)
})
```