All Projects β†’ lukechampine β†’ Freeze

lukechampine / Freeze

Licence: mit
An immutability helper for Go

Programming Languages

go
31211 projects - #10 most used programming language

Projects that are alternatives of or similar to Freeze

react-mlyn
react bindings to mlyn
Stars: ✭ 19 (-83.76%)
Mutual labels:  immutability
typescript-monads
πŸ“šWrite safer TypeScript using Maybe, List, Result, and Either monads.
Stars: ✭ 94 (-19.66%)
Mutual labels:  immutability
Dontfeartheprofunctoroptics
Don't Fear the Profunctor Optics!
Stars: ✭ 367 (+213.68%)
Mutual labels:  immutability
functional-js
Functional Programming in JavaScript
Stars: ✭ 18 (-84.62%)
Mutual labels:  immutability
immudb4j
Java SDK for immudb
Stars: ✭ 23 (-80.34%)
Mutual labels:  immutability
Mobx Keystone
A MobX powered state management solution based on data trees with first class support for Typescript, support for snapshots, patches and much more
Stars: ✭ 284 (+142.74%)
Mutual labels:  immutability
immutable-cursor
πŸ‘Š Immutable cursors incorporating the Immutable.js interface over a Clojure-inspired atom
Stars: ✭ 58 (-50.43%)
Mutual labels:  immutability
Immutable Tuple
Immutable finite list objects with constant-time equality testing (===) and no memory leaks.
Stars: ✭ 29 (-75.21%)
Mutual labels:  immutability
devonfw4flutter-mts-app
Large-Scale Flutter Reference Application. An Extension of DevonFw's My Thai Star Project
Stars: ✭ 54 (-53.85%)
Mutual labels:  immutability
Docile
Docile keeps your Ruby DSLs tame and well-behaved
Stars: ✭ 366 (+212.82%)
Mutual labels:  immutability
flutter built redux
Built_redux provider for Flutter.
Stars: ✭ 81 (-30.77%)
Mutual labels:  immutability
php-slang
The place where PHP meets Functional Programming
Stars: ✭ 107 (-8.55%)
Mutual labels:  immutability
Eslint Plugin Functional
ESLint rules to disable mutation and promote fp in JavaScript and TypeScript.
Stars: ✭ 282 (+141.03%)
Mutual labels:  immutability
Immutype
Immutability is easy!
Stars: ✭ 26 (-77.78%)
Mutual labels:  immutability
React Recollect
State management for React
Stars: ✭ 411 (+251.28%)
Mutual labels:  immutability
ftor
ftor enables ML-like type-directed, functional programming with Javascript including reasonable debugging.
Stars: ✭ 44 (-62.39%)
Mutual labels:  immutability
NonEmptyCollections
A type-safe implementation for collections that cannot be empty. Life is too short for emptiness-checks!
Stars: ✭ 45 (-61.54%)
Mutual labels:  immutability
Immutability Helper X
The library extends the kolodny/immutability-helper to support update data by path string, like the get/set in lodash.
Stars: ✭ 86 (-26.5%)
Mutual labels:  immutability
Tslint Immutable
TSLint rules to disable mutation in TypeScript.
Stars: ✭ 427 (+264.96%)
Mutual labels:  immutability
Prelude Ts
Functional programming, immutable collections and FP constructs for typescript and javascript
Stars: ✭ 315 (+169.23%)
Mutual labels:  immutability

Freeze

GoDoc Go Report Card

go get github.com/lukechampine/freeze

Package freeze enables the "freezing" of data, similar to JavaScript's Object.freeze(). A frozen object cannot be modified; attempting to do so will result in an unrecoverable panic.

Freezing is useful for providing soft guarantees of immutability. That is: the compiler can't prevent you from mutating an frozen object, but the runtime can. One of the unfortunate aspects of Go is its limited support for constants: structs, slices, and even arrays cannot be declared as consts. This becomes a problem when you want to pass a slice around to many consumers without worrying about them modifying it. With freeze, you can guard against these unwanted or intended behaviors.

To accomplish this, the mprotect syscall is used. Sadly, this necessitates allocating new memory via mmap and copying the data into it. This performance penalty should not be prohibitive, but it's something to be aware of.

In case it wasn't clear from the previous paragraph, this package is not intended to be used in production. A well-designed API is a much saner solution than freezing your data structures. I would even caution against using freeze in your automated testing, due to its platform-specific nature. freeze is best used for "one-off" debugging. Something like this:

  1. Observe bug
  2. Suspect that shared mutable data is the culprit
  3. Call freeze.Object on the data after it is created
  4. Run program again; it crashes
  5. Inspect stack trace to identify where the data was modified
  6. Fix bug
  7. Remove call to freeze.Object

Again: do not use freeze in production. It's a cool proof-of-concept, and it can be useful for debugging, but that's about it. Let me put it another way: freeze imports four packages: reflect, runtime, unsafe, and syscall (actually golang.org/x/sys/unix). Does that sound like a package you want to depend on?

Okay, back to the real documention:

Functions are provided for freezing the three "pointer types:" Pointer, Slice, and Map. Each function returns a copy of their input that is backed by protected memory. In addition, Object is provided for freezing recursively. Given a slice of pointers, Object will prevent modifications to both the pointer data and the slice data, while Slice merely does the latter.

To freeze an object:

type foo struct {
	X int
	y bool // yes, freeze works on unexported fields!
}
f := &foo{3, true}
f = freeze.Object(f).(*foo)
println(f.X) // ok; prints 3
f.X++        // not ok; panics

Note that since foo does not contain any pointers, calling Pointer(f) would have the same effect here.

It is recommended that, where convenient, you reassign the return value to its original variable, as with append. Otherwise, you will retain both the mutable original and the frozen copy.

Likewise, to freeze a slice:

xs := []int{1, 2, 3}
xs = freeze.Slice(xs).([]int)
println(xs[0]) // ok; prints 1
xs[0]++        // not ok; panics

Interfaces can also be frozen, since internally they are just pointers to objects. The effect of this is that the interface's pure methods can still be called, but impure methods cannot. Unfortunately, the impurity of a given method is defined by the implementation, not the interface. Even a String() method could conceivably modify some internal state. Furthermore, the caveat about unexported struct fields (see below) applies here, so many exported objects cannot be completely frozen.

Caveats

This package depends heavily on the internal representations of the slice and map types. These objects are not likely to change, but if they do, this package will break.

In general, you can't call Object on the same object twice. This is because Object will attempt to rewrite the object's internal pointers -- which is a memory modification. Calling Pointer or Slice twice should be fine.

Object cannot descend into unexported struct fields. It can still freeze the field itself, but if the field contains a pointer, the data it points to will not be frozen.

Appending to a frozen slice will trigger a panic iff len(slice) < cap(slice). This is because appending to a full slice will allocate new memory.

Unix is the only supported platform. Windows support is not planned, because it doesn't support a syscall analogous to mprotect.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].