racket/collects/teachpack/2htdp/scribblings/port.scrbl
Matthias Felleisen 6220900756 porting guide, please propagate to release
svn: r17759
2010-01-20 09:30:31 +00:00

369 lines
11 KiB
Racket

#lang scribble/doc
@(require "shared.ss"
"port.ss"
scribble/manual
(for-label scheme
(only-in 2htdp/universe on-tick on-draw)
(prefix-in htdp: teachpack/htdp/world)
(prefix-in htdp: htdp/image)
(prefix-in 2htdp: teachpack/2htdp/universe)
(prefix-in 2htdp: 2htdp/image)
(only-in lang/htdp-beginner check-expect)))
@; -----------------------------------------------------------------------------
@title[#:tag "htdp-port"]{Porting World Programs to Universe}
@author{Matthias Felleisen, Robby Findler}
@; -----------------------------------------------------------------------------
@section{The World is Not Enough}
With the June 2009 release, we started deprecating the world teachpack; instead
we recommended the use of the universe teachpack. With the January 2010 release,
we are also introducing a new image teachpack and, in support of this second
teachpack, we have separated out the image functionality from the
functionality for world programs.
In this document, we explain how to port programs that assume the old world
teachpack into this new setting, one step at a time. Most importantly,
programs must now import @emph{two} teachpacks insteead of one:
@port[
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname htdp/world))
))
@; ---------------------------------
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname 2htdp/universe))
(require #,(schememodname htdp/image))
))
]
The table shows the old style on the left and the new style on the
right. If your programs imported teachpacks via the drscheme teachpack
menu, we recommend that you use the @scheme[require] form from now on;
alternatively, you use the drscheme menu @emph{twice} to import the
functions from two teachpacks.
In the next section, we first explain how to port world programs so that
they use the universe teachpack and the @emph{old} image teachpack. In the
section after that, we list suggestions for changing programs so that they
no longer rely on the old image functionality but the new one.
In order to distinguish between the various pieces of functionality, we
uniformly prefix old functionality with "htdp:" and new functionality with
"2htdp:". There is no need to use these prefixes in your programs of
course.
@; -----------------------------------------------------------------------------
@section{Porting World Programs}
Here is the first program from the documentation for the world teachpack:
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname htdp/world))
;; Number -> Scene
(define (create-UFO-scene height)
(htdp:place-image UFO
50 height
(htdp:empty-scene 100 100)))
;; Scene
(define UFO
(htdp:overlay
(htdp:circle 10 'solid 'red)
(htdp:rectangle 40 4 'solid 'red)))
;; --- run program run
(htdp:big-bang 100 100 (/1 28) 0)
(htdp:on-tick-event add1)
(htdp:on-redraw create-UFO-scene)
))
This program defines a function for placing a @scheme[UFO] into a 100 by
100 scene, where @scheme[UFO] is a defined image. The world program itself
consists of three lines:
@itemize[
@item{the first one creates the 100 by 100 scene, specifies a rate of 28
images per second, and @scheme[0] as the initial world description;}
@item{the second one says that for each clock tick, the world (a number) is
increased by @scheme[1]; and}
@item{the last line tells drscheme to use @scheme[create-UFO-scene] as the
function that renders the current world as a scene.}
]
Let us now convert this program into the universe setting, step by
step, staring with the @scheme[require] specification, which is converted
as above:
@port[
@schemeblock[(require #,(schememodname htdp/world))]
@; ---------------------------------
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname 2htdp/universe))
(require #,(schememodname htdp/image))
))
]
The function that renders the world as a scene remains the same:
@port[
@(begin
#reader scribble/comment-reader
(schemeblock
;; Number -> Scene
(define (create-UFO-scene height)
(htdp:place-image
UFO
50 height
(htdp:empty-scene 100 100)))
))
@; ---------------------------------
@(begin
#reader scribble/comment-reader
(schemeblock
;; Number -> Scene
(define (create-UFO-scene height)
(htdp:place-image
UFO
50 height
(htdp:empty-scene 100 100)))
))
]
For the image constant we switch from symbols to strings:
@port[
@(begin
#reader scribble/comment-reader
(schemeblock
;; Scene
(define UFO
(htdp:overlay
(htdp:circle
10 'solid 'red)
(htdp:rectangle
40 4 'solid 'red)))
))
@; ---------------------------------
@(begin
#reader scribble/comment-reader
(schemeblock
;; Scene
(define UFO
(htdp:overlay
(htdp:circle
10 "solid" "red")
(htdp:rectangle
40 4 "solid" "red")))
))
]
Strictly speaking, this isn't necessary, but we intend to replace symbols
with strings whenever possible because strings are more common than
symbols.
The most important change concerns the lines that launch the world program:
@port[
@schemeblock[
(htdp:big-bang 100 100 (/1 28) 0)
(htdp:on-tick-event add1)
(htdp:on-redraw create-UFO-scene)
]
@; ---------------------------------
@schemeblock[
(2htdp:big-bang
0
(on-tick add1)
(on-draw create-UFO-scene))
]
]
They are turned into a single expression that comes with as many clauses
as there are lines in the old program. As you can see, the
@scheme[big-bang] expression from the universe teachpack no longer
requires the specification of the size of the scene or the rate at which
the clock ticks (though it is possible to supply the clock rate if the default
is not satisfactory).
Furthermore, the names of the clauses are similar to
the old names but shorter.
The other big change concerns key event handling and mouse event
handling. The respective handlers no longer accept symbols and chars but
strings only. Here is the first key event handler from the documentation
of the world teachpack:
@port[
@schemeblock[
(define (change w a-key-event)
(cond
[(key=? a-key-event 'left)
(world-go w -DELTA)]
[(key=? a-key-event 'right)
(world-go w +DELTA)]
[(char? a-key-event)
w]
[(key=? a-key-event 'up)
(world-go w -DELTA)]
[(key=? a-key-event 'down)
(world-go w +DELTA)]
[else
w]))]
@; ---------------------------------
@schemeblock[
(define (change w a-key-event)
(cond
[(key=? a-key-event "left")
(world-go w -DELTA)]
[(key=? a-key-event "right")
(world-go w +DELTA)]
[(= (string-length a-key-event) 1)
w]
[(key=? a-key-event "up")
(world-go w -DELTA)]
[(key=? a-key-event "down")
(world-go w +DELTA)]
[else
w]))
]]
Note how the @scheme[char?] clause changed. Since all chars are now
represented as strings containing one ``letter'', the program on the right
just checks the length of the string. Otherwise, we simply change all
symbols into strings.
If you ever recorded your programs' work via an animated gif, you can still
do so. Instead of adding a fifth argument to @scheme[big-bang], however,
you will need to add a clause of the shape @scheme[(record? x)].
Finally, the universe teachpack implements a richer functionality than the
world teachpack.
@; -----------------------------------------------------------------------------
@section{Porting Image Programs}
The universe library also comes with a new image library, @schememodname[2htdp/image].
Using the old image
library still works fine with @schememodname[2htdp/universe], but the
new image library provides a number of improvements, including faster
image comparison (especially useful in @scheme[check-expect] expressions),
rotating images, scaling images, curves, a number of new polygon shapes,
and more control over line drawing.
To use the new image library in isloation:
@port[
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname htdp/image))
))
@; ---------------------------------
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname 2htdp/image))
))
]
and to use the new image library with the universe teachpack:
@port[
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname htdp/world))
))
@; ---------------------------------
@(begin
#reader scribble/comment-reader
(schemeblock
(require #,(schememodname 2htdp/universe))
(require #,(schememodname 2htdp/image))
))]
@bold{Overlay vs Underlay}
The @scheme[htdp:overlay] function places its first argument
under its second (and subsequent) arguments and so in
@schememodname[2htdp/image], we decided to call that
function @scheme[2htdp:underlay].
@port[(schemeblock
(htdp:overlay
(htdp:rectangle
10 20 "solid" "red")
(htdp:rectangle
20 10 "solid" "blue")))
(schemeblock
(2htdp:underlay
(2htdp:rectangle
10 20 "solid" "red")
(2htdp:rectangle
20 10 "solid" "blue")))]
@bold{No more pinholes}
The concept of pinholes from @schememodname[htdp/image]
has no correspondance in @schememodname[2htdp/image]
(we do expect to bring back pinholes in @schememodname[2htdp/image]
eventually, but they will not be as pervasive as they are
in @scheme[htdp/image]).
Instead of
a special position in the image that overlay operations
are sensitive to,
@schememodname[2htdp/image] has a family of overlay operations,
that overlay images based on their centers or their edges.
Since the default position of the pinhole is in the center
for most images and the default for overlaying and underlaying
images in @scheme[2htdp/image] is based on the center,
simple examples (like the one above) behave the same
in both libraries.
But, consider this expression that overlays two images on
their upper-left corners, written using both libraries.
@port[@schemeblock[(htdp:overlay
(htdp:put-pinhole
(htdp:rectangle 10 20 "solid" "red")
0 0)
(htdp:put-pinhole
(htdp:rectangle 20 10 "solid" "blue")
0 0))]
@schemeblock[(2htdp:underlay/align
"left"
"top"
(2htdp:rectangle
10 20 "solid" "red")
(2htdp:rectangle
20 10 "solid" "blue"))]]
In the @schememodname[2htdp/image] version, the programmer
uses @scheme[2htdp:underlay/align] to specify where
the images should be lined up, instead of using the pinhole.
@bold{Outlines in different places}
The outline style shapes are now shifted by one pixel for @schememodname[2htdp/image]
images as compared to @schememodname[htdp/image].
This means that these two rectangles draw the same sets of pixels.
@port[@schemeblock[(htdp:rectangle
11 11 "outline" "black")]
@schemeblock[(2htdp:rectangle
10 10 "outline" "black")]]
See also @secref["nitty-gritty"].
@bold{Star changed}
The @scheme[2htdp:star] function is a completely different
function from @scheme[htdp:star]. Both produce stars based,
on polygons, but @scheme[2htdp:star] always produces a five-pointed
star. See also @scheme[2htdp:star-polygon] for more general star
shapes.