1.14 State🔗ℹ

Warning: If you are using Shplait with a programming-languages course, then the instructor has almost certainly disallowed the constructs in this chaper for use in your homework solutions, except as specifically allowed. Don’t use mutable, :=, block with more than one body expression, boxes, or arrays unless the instructor says that you can. If you’re tempted to use one of those, you’re doing it wrong.

We have so far described def as naming constants, but names bound by def mutable can be modified after the definition. The value associated to the name can be changed using the := operator.

def mutable gravity = 66

> gravity

- Int

66

> gravity := 65

- Void

> gravity

- Int

65

The type of a := expression is Void, meaning that it doesn’t return a useful value, and the useless value doesn’t even print as a result. If you need to change a variable and then return a value, use block to sequence the operations. The value of a block form is the value of its last expression.

def mutable counter = 0

fun fresh_number():

  block:

    counter := counter + 1

    counter

> fresh_number()

- Int

1

> fresh_number()

- Int

2

Although you can set a variable’s value using :=, you can’t directly pass a variable to another function that changes the variable’s value. Even if it were allowed syntactically, a := on a function’s argument would change the argument variable’s value, but would have no effect on the caller’s variables. To make a mutable location that can be passed around, Shplait supports boxes. You can think of a box as a mutable object that has a single field, where box creates a fresh object, unbox extracts the object’s field, and set_box changes the object’s field.

def counter1 = box(0)

def counter2 = box(0)

fun fresh_number_at(c):

  block:

    set_box(c, unbox(c) + 1)

    unbox(c)

> fresh_number_at(counter1)

- Int

1

> fresh_number_at(counter1)

- Int

2

> fresh_number_at(counter2)

- Int

1

> fresh_number_at(counter1)

- Int

3

An array is a traditional mutable array. Every element of an array must have the same type, which can be inferred from the value that you supply when making an array to serve as the initial value for each of the array’s slots. The make_array function creates an array, [] can be used after an array expression to access a slot of the array by position, and [] plus := changes a slot value by position.

def counters = make_array(2, 0)

fun fresh_number_at_index(i):

  block:

    counters[i] := counters[i] + 1

    counters[i]

> fresh_number_at_index(0)

- Int

1

> fresh_number_at_index(0)

- Int

2

> fresh_number_at_index(1)

- Int

1

> fresh_number_at_index(0)

- Int

3