(Im)mutability in the toolkit APIs #88
mickael-menu
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I'm starting this discussion in response to a PR fixing a data race in the toolkit, as we need to agree on a shared vision for the Go toolkit APIs.
I'm a proponent of immutability when possible, as it prevents some of the most challenging bugs: data races and race conditions. In my experience, it also makes the code more understandable as the data cannot change while we use it.
Both Swift and Kotlin toolkits have immutable models. We haven't come across a use case where mutability was truly necessary, but let me know if your mileage varies.
I'll end with a quote from Russ Cox (main maintainer of Go):
How to keep the toolkit immutable?
Prefer copy-by-value
I'm not advocating for hiding all the fields of a
struct
and exposing only read-only functions. Fortunately, Go uses a copy-by-value strategy with structs by default.So this fine, as a caller can change the property of a
var link: Link
locally, but this won't cause data races:However, we should avoid returning or referencing pointers.
The case for nullable values
The previous pattern is often used to represent a value that can be null.
Ideally we would use an
Optional<float64>
type, which might be feasible now that Go supports generics. But I don't think it's very idiomatic in the Go world?So I think it's fine to compromise and use
Position *float64
to represent an optional value, if we explicitly states that integrators should not mutate the value itself.That means that with
var contr: Contributor
, this is valid:But this should not be officially supported by the toolkit, as it mutates a shared reference:
Note that this is already the de facto behavior in the toolkit, except that we didn't explicitly said that we're not thread-safe.
Slices and maps
Unfortunately, slices and maps are copied by reference by default. So this is not safe, as we can modify the
map
concurrently:Here are some alternatives, by order of preference:
map
field and expose custom accessors (e.g.Link.GetProperty("authenticate")
).Beta Was this translation helpful? Give feedback.
All reactions