#lang scribble/manual @require[racket/include] @include{prelude.inc} @title{Background} @section{Network programming in the small} Even the simplest of programs can be seen as a network. This program sends a message containing @racket[3] and @racket[4] to @racket[+], and awaits a reply message, which contains @racket[7]: @interaction[(+ 3 4)] Subroutines are network services. Here, when the message @racket[3] is sent to @racket[add-four-to], it delegates to @racket[+]: @interaction[(define (add-four-to n) (+ n 4)) (add-four-to 3)] @note{In π-calculus encodings of programs, replication and state are made explicit.} Immutable programs (of which stateless programs are a special case) are easily able to be @emph{replicated}; programs using mutable state, however, must be fixed in place. In fact, strictly speaking, it is the @emph{state} that must be fixed in place, not the program @emph{manipulating} the state. In the following program, the mutable @racket[total] variable must not be replicated: @interaction[(define accumulate (let ((total 0)) (lambda (n) (set! total (+ total n)) total))) (accumulate 3) (accumulate 4) (accumulate 0)] It would be a mistake to simply replace each occurrence of @racket[accumulate] with its definition, since three separate @racket[total] locations would be created. However, there is no problem replicating the @racket[lambda] term, so long as @racket[total] always refers to the same location: @interaction[(define total 0) ((lambda (n) (set! total (+ total n)) total) 3) ((lambda (n) (set! total (+ total n)) total) 4) ((lambda (n) (set! total (+ total n)) total) 0)] Programs raise exceptions to signal partial failure: @interaction[(define accumulate (let ((total 0)) (lambda (n) (when (negative? n) (error 'accumulate "n must be non-negative!")) (set! total (+ total n)) total))) (accumulate 3) (accumulate -2)] Programs can handle exceptions to @emph{contain} partial failure: @interaction[(with-handlers ([exn:fail? (lambda (e) 'ok)]) (error 'oh-dear))] Partial failures interact with shared, mutable state in unpredictable ways, especially in larger programs that combine stateful subprograms. Programmers often ignore issues of security and trust between subprograms within a larger program. Most programming languages entirely lack any means of securely isolating subprograms from each other, leading to predictable failures. Even memory-safe languages such as Racket, Java and .NET only offer weak techniques for securely composing mutually suspicious subprograms. Techniques such as avoiding @emph{ambient authority} and using @emph{object capabilities} to compose subprograms TODO ^ @section{Network programming in the large} Programs which engage in I/O are very obviously part of a network: @racketblock[(define username (read-line)) (printf "Hello, ~a!\n" username)] But look closely! There is a difference here between the kind of communication This program is more obviously composed of a number of moving pieces: @interaction[(let ((b (box 3))) (set-box! b (+ (unbox b) 4)) (unbox b))] @interaction[(define (add-three-to b) (set-box! b (+ (unbox b) 3))) (define (add-four-to b) (set-box! b (+ (unbox b) 4))) (define my-box (box 0)) (add-three-to my-box) (add-four-to my-box) (unbox my-box)]