Skip to content

proposal: frozen slices / arrays / maps and derivatives (immutable subscript-able objects) #22048

Closed
@Spriithy

Description

@Spriithy

Disclaimer: I have knowledge of #20443 and the following proposes a different approach to the same problem

I would like Go to introduce three new builtin functions (as are new and make for instance). The idea behind those three functions is to provide Go's runtime with an efficient temporary immutable state for subscript-able objects (i.e. types that support indexing or key addressing t[...]). The concept is named object freezing and can be extended further to other types.

The functions

The first function is freeze(s Subscriptable) where Subscriptable is a documentation-purpose abstract type. It is used to freeze a subscript-able object.

t := make([]int, 10) // Create a slice of ints
t[0] = 10 // fine
freeze(t)
x := t[0] // fine, x = 10
t[1] = 2 // panics !
// optional
// unfreeze(t)

The second function is unfreeze(s Subscriptable) and is used to unfreeze a frozen object.

// using previously introduced slice t
unfreeze(t)
t[4] = 8 // fine

The third function is frozen(s Subscriptable) bool and returns whether an object is frozen.

t2 := make([]int, 10)
frozen(t2) // false
freeze(t2)
frozen(t2) // true
// optional
unfreeze(t2)

Freezing rules

Here is a set of rules of object freezing I can think of.

Any non-frozen object is said unfrozen.
A scope "owns the frost" of an object if it successfully froze it

  • A frozen object cannot be used as a left value
    • this makes freezing recursive
    • subscript & assign operation panics the current goroutine
    • accessing members (or indices) as r-values is OK
  • A frozen object cannot be assigned until it is unfrozen
  • A frozen object can be copied without problem
  • A frozen object can only be unfrozen within the scope that owns the frost
    • Unfreezing a non-scoped-frozen object panics the current goroutine
  • Freezing a frozen object doesn't give the current scope ownership of the frost
    • But it won't panic the goroutine
  • A frozen object is unfrozen before being garbage collected or when it falls out of scope

Rules Demonstration

Here I will demonstrate what it is possible (or not) using the above set of rules (using int slices).

func owns() {
    slice := make([]int, 10)
    freeze(slice)
    unfreeze(slice) // OK, slice was first frozen within this scope
}

func doesntOwn(slice []int) {
    unfreeze(slice) // panics if slice was frozen by call er
}

func wontBecomeOwner(slice []int) {
    freeze(slice) // won't give the ownership of the frost to this scope if 
                        // the slice was already frozen i.e. ... (won't panic either)
    unfreeze(slice) // ... will panic
}

func noLeftValue() {
    t := make([]int, 3)
    freeze(t)
    t[0] = 10 // Panic !
    unfreeze(t)
    
    // 3x3 matrix
    t2d := make([][]int, 3)
    t2d[0] = t 
    freeze(t2d)
    t2d[0][2] = 4 // Panic !
}

I know this is far from a complete / as accurate as possible proposal, but I hope it will give some insights into what I have been thinking about for a while. Feel free to point at possible loopholes I might have forgotten about !

Notes:

  • Of course all I have demonstrated using slices is applicable to maps, arrays and derived types of these (string, and custom types)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions