This page lists all known errors and their corrections for the first printing of the book. The errors in the most recent, fourth printing, are given here and the errors in the second and third printings are given here. If you find any new errors, please notify one of the authors. We use the following notation for the corrections: positive line numbers start counting from the top of the text body (including section titles); negative line numbers start counting from the bottom (including section titles and footnote text).
local Max in local C in Max=proc {$ ...} ... end local A in local B in A=3 B=5 {Max ...} end end end endThe translation given in the book does an additional source transformation that lifts all the local statements to be outermost.
fun {Sequence NonTerm Sep S1 Sn} fun {SequenceLoop Prefix S2 Sn} case S2 of T|S3 andthen {Sep T} then Next S4 in Next={NonTerm S3 S4} {SequenceLoop T(Prefix Next) S4 Sn} else Sn=S2 Prefix end end First S2 in First={NonTerm S1 S2} {SequenceLoop First S2 Sn} end
local Leak in {Unwrap fun {$ K} K=Leak unit end} endwill bind Leak to the key, which compromises the encapsulation. Data abstractions that use Unwrap are insecure because the internal calls to Unwrap can be exploited to leak the key. A correct definition of NewWrapper is:
proc {NewWrapper ?Wrap ?Unwrap} Key={NewName} in fun {Wrap X} {Chunk.new w(Key:X)} end fun {Unwrap W} try W.Key catch _ then raise error(unwrap(W)) end end end endThis uses a chunk, which is defined in Oz as a limited form of record that only supports the selection operator ".". This definition is secure because the W.Key operation cannot leak the value of Key, no matter what W is. Unlike what the book says on page 517 and in appendix B.4 (page 828), chunks cannot be defined with procedure values and names. Chunks are an additional concept that can be added to the kernel language. (Found by Tony Tanami Vågenes and Mark Miller.)
First, a read-only variable is created. Second, when the value of the read-only variable is needed (i.e., the program attempts to invoke a module operation), then the functor value is loaded from memory and called in a new thread with as arguments the modules it imports. This is called dynamic linking, as opposed to static linking in which the functor is installed when execution starts. Third, the functor call returns the new module and binds it to the variable.(Found by Gary T. Leavens.)
fun {Spawn P} Id Ok in thread Id={Thread.this} {Wait Ok} {P} end {Thread.suspend Id} Ok=unit Id end proc {Resume Id} Ok Me={Thread.this} in thread {Thread.suspend Me} Ok=unit {Thread.resume Id} end {Wait Ok} end(Found by Jeff Jackson.)
T(receive ... end Sin Sout) ≡ local fun {Loop S T#E Sout} if {IsDet S} then case S of M|S1 then case M of T(Pattern1) then E=S1 T(Body1 T Sout) ... [] T(PatternN) then E=S1 T(BodyN T Sout) else E1 in E=M|E1 {Loop S1 T#E1 Sout} end end else E=S T(BodyT T Sout) end end T in {Loop Sin T#T Sout} endThe loop is needed since the message removed from the mailbox is not necessarily the first.
fun {NewCollection} S={NewStack} proc {Put X} {S.push X} end fun {Get} {S.pop} end fun {IsEmpty} {S.isEmpty} end in collection(put:Put get:Get isEmpty:IsEmpty) endThe definition in the book has several small errors. (Found by Fred Spiessens.)
procedure sqr(a:integer); begin a:=a*a; end; var c:integer; c:=25; sqr(c); browse(c); /* value of c unchanged */with Oz translation:
proc {Sqr D} A={NewCell D} in A:=@A*@A end local C={NewCell 0} in C:=25 {Sqr @C} {Browse @C} /* content of C unchanged */ endThis gives a more reasonable definition of sqr and shows how to pass variables by value. (Found by Robert Godfroid.)
meth kill(X S) if @alive then if S==1 then @last=@ident elseif X mod @step==0 then alive:=false {@pred setSucc(@succ)} {@succ setPred(@pred)} {@succ kill(X+1 S-1)} else {@succ kill(X+1 S)} end else {@succ kill(X S)} end endThis works because the FIFO property guarantees that the setSucc and setPred messages arrive at their destinations before the kill messages.
fun {GetLock} if {Thread.this}\=@CurThr then Old New in {Exchange Token1 Old New} {Wait Old} Token2:=New CurThr:={Thread.this} true else false end end proc {LockM P} if {L.get} then try {P} finally {L.release} end else {P} end end proc {WaitM} X in {Q.insert X} {L.release} {Wait X} if {L.get} then skip end endThe new definition of GetLock will return true if it got the lock, and false otherwise. (Found by Jeff Jackson.)
proc {Palindrome ?A} B C X Y in A::0#9999 B::0#99 C::0#99 A=:B*C X::1#9 Y::0#9 A=:X*1000+Y*100+Y*10+X {FD.distribute ff [X Y B C]} endThe new definition solves exactly the same problem as the relational version in chapter 9 (page 629). The old definition solves a slightly different problem. (Found by Chris Rathman and Raphaël Collet.)
The arity of a record is the set of features of the record. The call {Arity R} executes as soon as R is bound to a record and returns the arity represented as a list of the features of the record sorted lexicographically.(Found by Waclaw Kusnierczyk.)