Last active
January 6, 2020 10:30
-
-
Save romshark/5d4650d837c1d87ef237e68ca1408280 to your computer and use it in GitHub Desktop.
If the Go programming language was immutable by default
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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