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?
We can make a place say hello. Enter the following in the definitions window of DrRacket, save the file and start interactions. Then call
#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.
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
Places can be started with
dynamic-place. Create a module in
#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)
You can synchronize with a place with
> (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
#lang racket/base (provide main) (require racket/place) (define (main c) (define m (place-channel-get c)) (place-channel-put c m) (main c)) > (define p (dynamic-place "test.rkt" 'main)) > (place-channel-put p "hello world") > (place-channel-get p)
You get a pair of channel-endpoints by using
(define-values (a b) (make-channel))
Channel endpoints can be sent to places.
Here, we talk about everything that can go wrong.
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
#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))