Skip to content

Instantly share code, notes, and snippets.

@romshark
Last active January 6, 2020 10:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romshark/5d4650d837c1d87ef237e68ca1408280 to your computer and use it in GitHub Desktop.
Save romshark/5d4650d837c1d87ef237e68ca1408280 to your computer and use it in GitHub Desktop.
If the Go programming language was immutable by default
package main
var globalImmutable = map[int]string{
1: "first",
2: "second",
3: "third",
}
func main() {
var x mut string = globalImmutable[1]
x = "another value"
y := globalImmutable[1]
y = "another value" // COMPILER ERROR
z := mut string(globalImmutable[1]) // OKAY, since it's a copy anyway
z = "another value"
globalImmutable[1] = "unknown" // COMPILER ERROR
delete(globalImmutable, 1) // COMPILER ERROR
globalImmutable = map[int]string{} // COMPILER ERROR
mutableS := newS()
mutableS.Reset()
takeMut(mutableS)
takeMutPtr(mutableS)
// mut S can't be casted to S since S.children contains mutable references
takeImmut(mutableS) // COMPILER ERROR
immutableS := &S{}
immutableS.Reset() // COMPILER ERROR, receiver is mutable
immutableS.x = 42 // COMPILER ERROR
casted := * mut S(immutableS) // COMPILER ERROR, can't cast away immutability on pointer
takeMutPtr(immutableS) // COMPILER ERROR, can't pass pointer to immutable S
}
// S represents a partially mutable data structure
// where the id cannot be assigned after S is created
// just as well as the list of children,
// yet the children themselfes are mutable
type S struct {
id string
x mut int
y mut int
children [] * mut S
}
func (s * mut S) Reset() {
s.x = 0
s.y = 0
s.children = [] * mut S {} // COMPILER ERROR
s.children = append(s.children, & mut S{}) // COMPILER ERROR
for _, childPtr := range s.children {
childPtr.x = 0
childPtr.y = 0
}
}
func (s mut * S) String() string {
return fmt.Sprintf("%s(%d:%d)", s.id, s.x, s.y)
}
func newS() mut S {
return mut S{id: "immutable_idenfier"}
}
func takeImmut(i S) {
i.y = 42 // COMPILER ERROR, i is immutable
i = S{} // COMPILER ERROR, i is immutable
}
func takeMut(s mut S) {
s.y = 42
s.id = "new" // COMPILER ERROR, S.id is an immutable field
}
func takeMutPtr(mutable * mut S) {
mutable.x = 42
mutable.y = 42
}
/**** MIXED MUTABILITY TYPES ****/
// globalMixed is an immutable slice of mutable slices of integers
var globalMixed = [] mut [] int {
{1,2,3},
{4,5,6},
{7,8,9},
}
func init() {
globalMixed[0] = []int{} // COMPILER ERROR
globalMixed = [] mut []int{} // COMPILER ERROR
globalMixed[0][0] = 42
}
/**** IMPLICIT IMMUT -> MUT CASTING ****/
// immutables are implicitly casted to mutable when they can be safely copied
// (when they don't contain any references)
func implicitCasting() {
type Z struct {
ID string
Number float64
}
var (
immutable Z
mutable mut Z
immutableSl []int
mutableSl mut []int
ptrToImmutable *Z
ptrToMutable mut * mut Z
immutablePtr *Z
mutablePtr mut *Z
)
// Pure structs can be cast implicitly since they're safely copied on assignment
mutable = immutable // OKAY
// Slices aren't copied on assignment, thus they cannot be cast implicitly
mutableSl = immutableSl // COMPILER ERROR
// The immutable Z pointed to by ptrToImmutable can't be exposed
// as mutable through ptrToMutable, therefore it can't be cast implicitly
ptrToMutable = ptrToImmutable // COMPILER ERROR
// Pointers are copied and since they both point to immutable Z's they're cast implicitly
mutablePtr = immutablePtr // OKAY
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment