Racket Places
2019-02-05
A Racket place is an independent process in Racket. Places interact by sending messages.
Besides places Racket provides a few other similar concepts:
What are the differences between places, threads, and futures? When would you use the one or the other?
Hello world
We can make a place say hello. Enter the following in the definitions window of DrRacket, save the file and start interactions. Then call (say-hello)
#lang racket/base
(require racket/place)
(define (say-hello)
(define p (place _ (displayln "hello world")))
(place-wait p))
There is already a lot of things going on.
couldn’t we create a place in the interactive window?
couldn’t we start the place in the top level of the module?
couldn’t we call
(say-hello)
already in the module?what happens if you do not save your editor?
From now on, we use dynamic-place
instead of place
to create new places.
Basic concepts
Racket places talk about three things:
- place
an independent instance of a Racket VM
- channel
a handle to send and receive messages; they usually come in pairs
- message
a Racket value we can pass around between places
Place life cycle
dynamic-place
Places can be started with dynamic-place
. Create a module in place-module.rkt
.
#lang racket/base
(provide main)
(require racket/place)
(define (main c)
(displayln "hello world"))
Then, in the interactive window, start the place by entering
(dynamic-place "place-module.rkt" 'main)
place-wait
You can synchronize with a place with place-wait
.
(define p (dynamic-place "place-module.rkt" 'main)
(place-wait p)
Sending and Receiving Messages
Let’s make a server that receives a message and prints it on the screen. For receiving we use place-channel-get
. Sending uses place-channel-put
. Store the following code in a file test.rkt
:
#lang racket/base
(provide main)
(require racket/place)
(define (main c)
(define m
(place-channel-get c))
(place-channel-put c m)
(main c))
Now, on the repl, enter:
(define p (dynamic-place “test.rkt” ‘main)) (place-channel-put p “hello world”) (place-channel-get p)
Creating Channels
You get a pair of channel-endpoints by using place-channel
.
(define-values (a b) (make-channel))
Channel endpoints can be sent to places.
Trouble Shooting
Here, we talk about everything that can go wrong.
Error Jeopardy
place: can only be used in a module
You have tried to create a place in the interactions window of DrRacket. But places can be started only in the definitions window.
place: the enclosing module's resolved name is not a path or predefined
You need to save your definitions window to disk.
syntax-local-lift-provide: not expanding in a module run-time body
You have tried to define a serializable function, a serial-lambda), in the interactions window of DrRacket. But serializable functions can be defined only in the definitions window.
place-channel-put: value not allowed in a message
You have tried to send a value over a channel that is not message-allowed. Racket forbids to send values like functions or opaque structures. You can find out if a value is message-allowed by testing it with place-message-allowed?.
Message Passing and Serializability
While for many Racket values it is obvious whether or why they can be sent over a channel guessing what values are allowed as messages can be difficult. Surprisingly, neither does serializability imply message-allowedness nor the other way around.
For example, apparently the exact integer 5
is both message-allowed and serializable. In contrast, the function (lambda (x) x)
is neither message-allowed nor serializable.
However, some values are message-allowed but not serializable. For example place identifiers are:
#lang racket/base
(require racket/place)
(require racket/serialize)
(define p
(place c (displayln "hello world")))
(serializable? p) ; #f
(place-channel-allowed? p) ; #t
Also, some values are serializable but not message-allowed. For example serial-lambdas are:
#lang racket/base
(require web-server/lang/serial-lambda
racket/serialize
racket/place)
(define f
(serial-lambda (x) x))
(serializable? f) ; #t
(place-message-allowed? f) ; #f
So don’t forget to serialize your serializable functions.
Message Passing and Structs
Structs must be #:prefab
to send them over a channel. Note that #:transparent
structs are false friends being neither message-allowed nor serializable.
Sending and Receiving Functions
Racket forbids to send functions over place channels. To circumvent this problem we can use the serializable functions provided by web-server/lang/serial-lambda
.
#lang racket/base
(require racket/serialize)
(require racket/place)
(require web-server/lang/serial-lambda)
(define c
(place
c
(define f
(deserialize (place-channel-get c)))
(f)))
(define f
(serial-lambda () (displayln "hello world")))
(place-channel-put c (serialize f))