Pointers in Racket

In Racket, we don’t have explicit pointers like in some other languages. Instead, we can use mutable data structures to achieve similar effects. Let’s explore this concept using mutable boxes.

#lang racket

(require racket/box)

; We'll show how mutable boxes work in contrast to values with
; 2 functions: 'zeroval' and 'zerobox'. 'zeroval' has a
; number parameter, so arguments will be passed to it by
; value. 'zeroval' will get a copy of 'ival' distinct
; from the one in the calling function.
(define (zeroval ival)
  (set! ival 0))

; 'zerobox' in contrast has a box parameter, which is mutable.
; The 'set-box!' function in the function body then changes
; the value stored in the box. This is similar to dereferencing
; a pointer and changing the value at that address.
(define (zerobox ibox)
  (set-box! ibox 0))

(define (main)
  (define i 1)
  (printf "initial: ~a\n" i)
  
  (zeroval i)
  (printf "zeroval: ~a\n" i)
  
  ; The 'box' function creates a new mutable box containing the value.
  ; This is similar to getting a pointer to 'i'.
  (zerobox (box i))
  (printf "zerobox: ~a\n" i)
  
  ; We can print the box itself, which shows it's a different type
  ; than the value it contains.
  (printf "box: ~a\n" (box i)))

(main)

To run this program, save it to a file (e.g., mutable-boxes.rkt) and use the Racket interpreter:

$ racket mutable-boxes.rkt
initial: 1
zeroval: 1
zerobox: 1
box: #&1

zeroval doesn’t change the i in main, but zerobox does change the value of i. However, note that in this Racket example, we’re not actually changing i directly in main. To do that, we would need to use a more complex structure or a parameter. This example demonstrates the concept of mutable state, which is the closest equivalent to pointers in Racket.

In Racket, most data is immutable by default, which is different from languages with explicit pointers. When you need mutable state, you use specific constructs like boxes or other mutable data structures. This approach helps manage side effects and makes programs easier to reason about, but it requires a different way of thinking about state and references compared to pointer-based languages.