1#lang scribble/doc
2@(require "mz.rkt")
3
4@(define-syntax op
5  (syntax-rules ()
6    [(_ (x ...)) (x ...)]
7    [(_ id) @racket[id]]))
8@(define-syntax-rule (operations i ...)
9   (itemlist #:style 'compact @item{@op[i]} ...))
10
11@title[#:tag "chaperones"]{Impersonators and Chaperones}
12
13An @deftech{impersonator} is a wrapper for a value where the wrapper
14redirects some of the value's operations. Impersonators apply only to procedures,
15@tech{structures} for which an accessor or mutator is available,
16@tech{structure types}, @tech{hash tables}, @tech{vectors},
17@tech{box}es, @tech{channels}, and @tech{prompt tag}s.
18An impersonator is @racket[equal?] to the original
19value, but not @racket[eq?] to the original value.
20
21A @deftech{chaperone} is a kind of impersonator whose refinement of a value's
22operation is restricted to side effects (including, in particular,
23raising an exception) or chaperoning values supplied to or produced by
24the operation. For example, a vector chaperone can redirect
25@racket[vector-ref] to raise an exception if the accessed vector slot
26contains a string, or it can cause the result of @racket[vector-ref]
27to be a chaperoned variant of the value that is in the accessed vector
28slot, but it cannot redirect @racket[vector-ref] to produce a value
29that is arbitrarily different from the value in the vector slot.
30
31A non-@tech{chaperone} @tech{impersonator}, in contrast, can refine an operation to swap one
32value for any other. An impersonator cannot be applied to an immutable value
33or refine the access to an immutable field in an instance of a @tech{structure
34type}, since arbitrary redirection of an operation amounts to
35mutation of the impersonated value.
36
37Beware that each of the following operations can be redirected to an
38arbitrary procedure through an impersonator on the operation's
39argument---assuming that the operation is available to the creator of
40the impersonator:
41
42@operations[@t{a structure-field accessor}
43            @t{a structure-field mutator}
44            @t{a structure type property accessor}
45            @t{application of a procedure}
46            unbox set-box!
47            vector-ref vector-set!
48            hash-ref hash-set hash-set! hash-remove hash-remove!
49            channel-get channel-put
50            call-with-continuation-prompt
51            abort-current-continuation]
52
53Derived operations, such as printing a value, can be redirected
54through impersonators due to their use of accessor functions. The
55@racket[equal?], @racket[equal-hash-code], and
56@racket[equal-secondary-hash-code] operations, in contrast, may bypass
57impersonators (but they are not obliged to).
58
59In addition to redirecting operations that work on a value, a
60impersonator can include @deftech{impersonator properties} for an impersonated
61value. An @tech{impersonator property} is similar to a @tech{structure
62type property}, but it applies to impersonators instead of structure
63types and their instances.
64
65
66@defproc[(impersonator? [v any/c]) boolean?]{
67
68Returns @racket[#t] if @racket[v] is an @tech{impersonator} created by
69procedures like @racket[impersonate-procedure] or
70@racket[impersonate-struct], @racket[#f] otherwise.
71
72Programs and libraries generally should avoid @racket[impersonator?] and
73treat impersonators the same as non-impersonator values. In rare cases,
74@racket[impersonator?] may be needed to guard against redirection by an
75impersonator of an operation to an arbitrary procedure.
76
77A limitation of @racket[impersonator?] is that it does @emph{not}
78recognize an @tech{impersonator} that is created by instantiating a
79structure type with the @racket[prop:impersonator-of] property. The
80limitation reflects how those impersonators cannot redirect structure
81access and mutation operations to arbitrary procedures.}
82
83
84@defproc[(chaperone? [v any/c]) boolean?]{
85
86Returns @racket[#t] if @racket[v] is a @tech{chaperone}, @racket[#f] otherwise.
87
88Programs and libraries generally should avoid @racket[chaperone?] for
89the same reason that they should avoid @racket[impersonator?]. A true
90value for @racket[chaperone?] implies a true value of
91@racket[impersonator?].}
92
93
94@defproc[(impersonator-of? [v1 any/c] [v2 any/c]) boolean?]{
95
96Indicates whether @racket[v1] can be considered equivalent modulo
97impersonators to @racket[v2].
98
99Any two values that are @racket[eq?] to one another are also @racket[impersonator-of?].
100For values that include no impersonators, @racket[v1] and @racket[v2] are
101considered impersonators of each other if they are @racket[equal?].
102
103If at least one of @racket[v1] or @racket[v2] is an impersonator:
104@itemlist[
105          @item{If @racket[v1] impersonates @racket[_v1*] then @racket[(impersonator-of? v1 v2)]
106                   is @racket[#t] if and only if @racket[(impersonator-of? _v1* v2)] is @racket[#t].}
107          @item{If @racket[v2] is a non-interposing impersonator that impersonates @racket[_v2*], i.e.,
108                   all of its interposition procedures are @racket[#f], then @racket[(impersonator-of? v1 v2)]
109                   is @racket[#t] if and only if @racket[(impersonator-of? v1 _v2*)] is @racket[#t].}
110          @item{When @racket[v2] is an impersonator constructed with at least one non-@racket[#f] interposition procedure,
111                     but @racket[v1] is not an impersonator then @racket[(impersonator-of? v1 v2)] is @racket[#f].}]}
112
113Otherwise, if neither @racket[_v1] or @racket[_v2] is an impersonator, but either
114of them contains an impersonator as a subpart (e.g., @racket[_v1] is a list with
115an impersonator as one of its elements), then @racket[(impersonator-of? _v1 _v2)]
116proceeds by comparing @racket[_v1] and @racket[_v2] recursively (as with
117@racket[equal?]), returning true if all subparts are @racket[impersonator-of?].
118
119@examples[
120(impersonator-of? (impersonate-procedure add1 (λ (x) x))
121                  add1)
122(impersonator-of? (impersonate-procedure add1 (λ (x) x))
123                  sub1)
124(impersonator-of? (impersonate-procedure
125                    (impersonate-procedure add1 (λ (x) x)) (λ (x) x))
126                  add1)
127(impersonator-of? (impersonate-procedure add1 (λ (x) x))
128                  (impersonate-procedure add1 #f))
129(impersonator-of? (impersonate-procedure add1 (λ (x) x))
130                  (impersonate-procedure add1 (λ (x) x)))
131(impersonator-of? (list 1 2)
132                  (list 1 2))
133(impersonator-of? (list (impersonate-procedure add1 (λ (x) x)) sub1)
134                  (list add1 sub1))
135]
136
137@defproc[(chaperone-of? [v1 any/c] [v2 any/c]) boolean?]{
138
139Indicates whether @racket[v1] can be considered equivalent modulo
140chaperones to @racket[v2].
141
142For values that include no chaperones or other impersonators,
143@racket[v1] and @racket[v2] can be considered chaperones of each other
144if they are @racket[equal?], except that corresponding mutable
145vectors, boxes, strings, byte strings, and mutable structures within
146@racket[v1] and @racket[v2] must be @racket[eq?].
147
148Otherwise, chaperones and other impersonators within @racket[v2] must
149be intact within @racket[v1] analogous to way that
150@racket[impersonator-of?] requires that impersonators are preserved.
151Furthermore, @racket[v1] must not have any non-chaperone impersonators
152whose corresponding value in @racket[v2] is not the same impersonator.
153Note that @racket[chaperone-of?] implies @racket[impersonator-of?],
154but not vice-versa.}
155
156
157@defproc[(impersonator-ephemeron [v any/c]) ephemeron?]{
158
159Produces an @tech{ephemeron} that can be used to connect the
160reachability of @racket[v] (in the sense of garbage collection; see
161@secref["gc-model"]) with the reachability of any value for which
162@racket[v] is an @tech{impersonator}. That is, the value @racket[v]
163will be considered reachable as long as the result ephemeron is
164reachable in addition to any value that @racket[v] impersonates
165(including itself).}
166
167@defproc[(procedure-impersonator*? [v any/c]) boolean?]{
168
169Returns @racket[#t] for any procedure impersonator that either was produced by
170@racket[impersonate-procedure*] or @racket[chaperone-procedure*], or is
171an impersonator/chaperone of a value that was created with
172@racket[impersonate-procedure*] or @racket[chaperone-procedure*]
173(possibly transitively).}
174
175@; ------------------------------------------------------------
176@section{Impersonator Constructors}
177
178@defproc[(impersonate-procedure [proc procedure?]
179                                [wrapper-proc (or/c procedure? #f)]
180                                [prop impersonator-property?]
181                                [prop-val any/c] ... ...)
182         (and/c procedure? impersonator?)]{
183
184Returns an impersonator procedure that has the same arity, name, and
185other attributes as @racket[proc]. When the impersonator procedure is
186applied, the arguments are first passed to @racket[wrapper-proc]
187(when it is not @racket[#f]), and
188then the results from @racket[wrapper-proc] are passed to
189@racket[proc]. The @racket[wrapper-proc] can also supply a procedure
190that processes the results of @racket[proc].
191
192The arity of @racket[wrapper-proc] must include the arity of
193@racket[proc]. The allowed keyword arguments of @racket[wrapper-proc]
194must be a superset of the allowed keywords of @racket[proc]. The
195required keyword arguments of @racket[wrapper-proc] must be a subset
196of the required keywords of @racket[proc].
197
198For applications without keywords, the result of @racket[wrapper-proc]
199must be at least the same number of values as supplied to it.
200Additional results can be supplied---before the values that correspond
201to the supplied values---in the following pattern:
202
203@itemlist[
204
205 @item{An optional procedure, @racket[_result-wrapper-proc], which
206       will be applied to the results of @racket[proc]; followed by}
207
208 @item{any number of repetitions of @racket['mark _key _val] (i.e.,
209       three values), where the call @racket[_proc] is wrapped to
210       install a @tech{continuation mark} @racket[_key] and @racket[_val].}
211
212]
213
214If @racket[_result-wrapper-proc] is produced, it must be a procedure
215that accepts as many results as produced by @racket[proc]; it must
216return the same number of results. If @racket[_result-wrapper-proc] is
217not supplied, then @racket[proc] is called in @tech{tail position}
218with respect to the call to the impersonator.
219
220For applications that include keyword arguments, @racket[wrapper-proc]
221must return an additional value before any other values but after
222@racket[_result-wrapper-proc] and @racket['mark _key _val]
223sequences (if any). The additional value must be a
224list of replacements for the keyword arguments that were supplied to the
225impersonator (i.e., not counting optional arguments that were
226not supplied). The arguments must be ordered according to the sorted
227order of the supplied arguments' keywords.
228
229If @racket[wrapper-proc] is @racket[#f], then applying the resulting
230impersonator is the same as applying @racket[proc]. If
231@racket[wrapper-proc] is @racket[#f] and no @racket[prop] is provided, then
232@racket[proc] is returned and is not impersonated.
233
234Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
235to @racket[impersonate-procedure] must be even) add impersonator properties
236or override impersonator-property values of @racket[proc].
237
238If any @racket[prop] is @racket[impersonator-prop:application-mark] and if the
239associated @racket[prop-val] is a pair, then the call to @racket[proc]
240is wrapped with @racket[with-continuation-mark] using @racket[(car
241prop-val)] as the mark key and @racket[(cdr prop-val)] as the mark
242value. In addition, if the immediate
243continuation frame of the call to the impersonated procedure
244includes a value for @racket[(car prop-val)]---that is, if
245@racket[call-with-immediate-continuation-mark] would produce a value
246for @racket[(car prop-val)] in the call's continuation---then the value is
247also installed as an immediate value for @racket[(car prop-val)] as a
248mark during the call to @racket[wrapper-proc] (which allows tail-calls
249of impersonators with respect to wrapping impersonators to be detected within
250@racket[wrapper-proc]).
251
252@history[#:changed "6.3.0.5" @elem{Added support for @racket['mark
253                                   _key _val] results from
254                                   @racket[wrapper-proc].}]
255
256 @examples[
257
258 (define (add15 x) (+ x 15))
259 (define add15+print
260   (impersonate-procedure add15
261                          (λ (x)
262                            (printf "called with ~s\n" x)
263                            (values (λ (res)
264                                      (printf "returned ~s\n" res)
265                                      res)
266                                    x))))
267 (add15 27)
268 (add15+print 27)
269
270 (define-values (imp-prop:p1 imp-prop:p1? imp-prop:p1-get)
271   (make-impersonator-property 'imp-prop:p1))
272 (define-values (imp-prop:p2 imp-prop:p2? imp-prop:p2-get)
273   (make-impersonator-property 'imp-prop:p2))
274
275 (define add15.2 (impersonate-procedure add15 #f imp-prop:p1 11))
276 (add15.2 2)
277 (imp-prop:p1? add15.2)
278 (imp-prop:p1-get add15.2)
279 (imp-prop:p2? add15.2)
280
281 (define add15.3 (impersonate-procedure add15.2 #f imp-prop:p2 13))
282 (add15.3 3)
283 (imp-prop:p1? add15.3)
284 (imp-prop:p1-get add15.3)
285 (imp-prop:p2? add15.3)
286 (imp-prop:p2-get add15.3)
287
288 (define add15.4 (impersonate-procedure add15.3 #f imp-prop:p1 101))
289 (add15.4 4)
290 (imp-prop:p1? add15.4)
291 (imp-prop:p1-get add15.4)
292 (imp-prop:p2? add15.4)
293 (imp-prop:p2-get add15.4)]
294}
295
296@defproc[(impersonate-procedure* [proc procedure?]
297                                 [wrapper-proc (or/c procedure? #f)]
298                                 [prop impersonator-property?]
299                                 [prop-val any/c] ... ...)
300         (and/c procedure? impersonator?)]{
301
302Like @racket[impersonate-procedure], except that @racket[wrapper-proc]
303receives an additional argument before all other arguments. The
304additional argument is the procedure @racket[_orig-proc] that was
305originally applied.
306
307If the result of @racket[impersonate-procedure*] is applied directly,
308then @racket[_orig-proc] is that result. If the result is further
309impersonated before being applied, however, @racket[_orig-proc] is the
310further impersonator.
311
312An @racket[_orig-proc] argument might be useful so that
313@racket[wrapper-proc] can extract @tech{impersonator properties}
314that are overridden by further impersonators, for example.
315
316@history[#:added "6.1.1.5"]}
317
318
319@defproc[(impersonate-struct [v any/c]
320                             [struct-type struct-type? _unspecified]
321                             [orig-proc (or/c struct-accessor-procedure?
322                                              struct-mutator-procedure?
323                                              struct-type-property-accessor-procedure?)]
324                             [redirect-proc (or/c procedure? #f)] ... ...
325                             [prop impersonator-property?]
326                             [prop-val any/c] ... ...)
327          any/c]{
328
329Returns an impersonator of @racket[v], which redirects certain
330operations on the impersonated value. The @racket[orig-proc]s
331indicate the operations to redirect, and the corresponding
332@racket[redirect-proc]s supply the redirections. The optional
333@racket[struct-type] argument, when provided, acts as a witness for
334the representation of @racket[v], which must be an instance of
335@racket[struct-type].
336
337The protocol for a @racket[redirect-proc] depends on the corresponding
338@racket[orig-proc], where @racket[_self] refers to the value to which
339@racket[orig-proc] is originally applied:
340
341@itemlist[
342
343 @item{A structure-field accessor: @racket[redirect-proc]
344      must accept two arguments, @racket[_self] and the value
345      @racket[_field-v] that @racket[orig-proc] produces for
346      @racket[v]; it must return a replacement for
347      @racket[_field-v]. The corresponding field must not be
348      immutable, and either the field's structure type must be
349      accessible via the current @tech{inspector} or one of the other
350      @racket[orig-proc]s must be a structure-field mutator for the
351      same field.}
352
353 @item{A structure-field mutator: @racket[redirect-proc] must accept
354      two arguments, @racket[_self] and the value @racket[_field-v]
355      supplied to the mutator; it must return a replacement for
356      @racket[_field-v] to be propagated to @racket[orig-proc] and
357      @racket[v].}
358
359 @item{A property accessor: @racket[redirect-proc] uses the same
360       protocol as for a structure-field accessor. The accessor's
361       property must have been created with @racket['can-impersonate]
362       as the second argument to @racket[make-struct-type-property].}
363
364]
365
366When a @racket[redirect-proc] is @racket[#f], the corresponding
367@racket[orig-proc] is unaffected. Supplying @racket[#f] for a
368@racket[redirect-proc] is useful to allow its @racket[orig-proc] to
369act as a ``witness'' of @racket[v]'s representation and enable the
370addition of @racket[prop]s.
371
372Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
373to @racket[impersonate-struct] must be even if @racket[struct-type]
374is provided, odd otherwise) add impersonator properties
375or override impersonator-property values of @racket[v].
376
377Each @racket[orig-proc] must indicate a distinct operation. If no
378@racket[struct-type] and no @racket[orig-proc]s are supplied, then no @racket[prop]s must be
379supplied. If @racket[orig-proc]s are supplied only with @racket[#f]
380@racket[redirect-proc]s and no @racket[prop]s are supplied, then
381@racket[v] is returned and is not impersonated.
382
383If any @racket[orig-proc] is itself an impersonator, then a use of the
384accessor or mutator that @racket[orig-proc] impersonates is redirected
385for the resulting impersonated structure to use @racket[orig-proc] on
386@racket[v] before @racket[redirect-proc] (in the case of accessor) or
387after @racket[redirect-proc] (in the case of a mutator).
388
389@history[#:changed "6.1.1.2" @elem{Changed first argument to an
390                                   accessor or mutator
391                                   @racket[redirect-proc] from
392                                   @racket[v] to @racket[_self].}
393         #:changed "6.1.1.8" @elem{Added optional @racket[struct-type]
394                                   argument.}]}
395
396
397@defproc[(impersonate-vector [vec (and/c vector? (not/c immutable?))]
398                             [ref-proc (or/c (vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
399                             [set-proc (or/c (vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
400                             [prop impersonator-property?]
401                             [prop-val any/c] ... ...)
402          (and/c vector? impersonator?)]{
403
404Returns an impersonator of @racket[vec], which redirects the
405@racket[vector-ref] and @racket[vector-set!] operations.
406
407The @racket[ref-proc] and @racket[set-proc] arguments must either both be procedures
408or both be @racket[#f]. If they are @racket[#f] then @racket[impersonate-vector] does not interpose
409on @racket[vec], but still allows attaching impersonator properties.
410
411If @racket[ref-proc] is a procedure it must accept @racket[vec], an index passed to
412@racket[vector-ref], and the value that @racket[vector-ref] on
413@racket[vec] produces for the given index; it must produce a
414replacement for the value, which is the result of @racket[vector-ref]
415on the impersonator.
416
417If @racket[set-proc] is a procedure it must accept @racket[vec], an index passed to
418@racket[vector-set!], and the value passed to @racket[vector-set!]; it
419must produce a replacement for the value, which is used
420with @racket[vector-set!] on the original @racket[vec] to install the
421value.
422
423Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
424to @racket[impersonate-vector] must be odd) add impersonator properties
425or override impersonator-property values of @racket[vec].
426
427@history[#:changed "6.9.0.2"]{Added non-interposing vector impersonators.}
428}
429
430@defproc[(impersonate-vector* [vec (and/c vector? (not/c immutable?))]
431                              [ref-proc (or/c (vector? vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
432                              [set-proc (or/c (vector? vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
433                              [prop impersonator-property?]
434                              [prop-val any/c] ... ...)
435          (and/c vector? impersonator?)]{
436 Like @racket[impersonate-vector], except that @racket[ref-proc] and @racket[set-proc] each receive
437 an additional vector as argument before other arguments. The additional argument is the original
438 impersonated vector, access to which triggered interposition in the first place.
439
440 The additional vector argument might be useful so that @racket[ref-proc] or @racket[set-proc]
441 can extract impersonator properties that are overridden by further impersonators, for example.
442
443 @history[#:added "6.9.0.2"]
444}
445
446@defproc[(impersonate-box [box (and/c box? (not/c immutable?))]
447                          [unbox-proc (box? any/c . -> . any/c)]
448                          [set-proc (box? any/c . -> . any/c)]
449                          [prop impersonator-property?]
450                          [prop-val any/c] ... ...)
451          (and/c box? impersonator?)]{
452
453Returns an impersonator of @racket[box], which redirects the
454@racket[unbox] and @racket[set-box!] operations.
455
456The @racket[unbox-proc] must accept @racket[box] and the value that
457@racket[unbox] produces on @racket[box]; it must produce a replacement
458value, which is the result of @racket[unbox] on the impersonator.
459
460The @racket[set-proc] must accept @racket[box] and the value passed to
461@racket[set-box!]; it must produce a replacement
462value, which is used with @racket[set-box!] on the original
463@racket[box] to install the value.
464
465Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
466to @racket[impersonate-box] must be odd) add impersonator properties
467or override impersonator-property values of @racket[box].}
468
469
470@defproc[(impersonate-hash [hash (and/c hash? (not/c immutable?))]
471                           [ref-proc (hash? any/c . -> . (values
472                                                          any/c
473                                                          (hash? any/c any/c . -> . any/c)))]
474                           [set-proc (hash? any/c any/c . -> . (values any/c any/c))]
475                           [remove-proc (hash? any/c . -> . any/c)]
476                           [key-proc (hash? any/c . -> . any/c)]
477                           [clear-proc (or/c #f (hash? . -> . any)) #f]
478                           [equal-key-proc (or/c #f (hash? any/c . -> . any/c)) #f]
479                           [prop impersonator-property?]
480                           [prop-val any/c] ... ...)
481          (and/c hash? impersonator?)]{
482
483Returns an impersonator of @racket[hash], which redirects the
484@racket[hash-ref], @racket[hash-set!] or @racket[hash-set] (as
485applicable), @racket[hash-remove] or @racket[hash-remove!] (as
486applicable), @racket[hash-clear] or @racket[hash-clear!] (as
487applicable and if @racket[clear-proc] is not @racket[#f]) operations. When
488@racket[hash-set], @racket[hash-remove] or @racket[hash-clear] is used on an impersonator of a hash
489table, the result is an impersonator with the same redirecting procedures.
490In addition, operations like
491@racket[hash-iterate-key] or @racket[hash-map], which extract
492keys from the table, use @racket[key-proc] to replace keys extracted
493from the table. Operations like @racket[hash-iterate-value] or
494@racket[hash-values] implicitly use @racket[hash-ref] and
495therefore redirect through @racket[ref-proc]. The @racket[hash-ref-key]
496operation uses both @racket[ref-proc] and @racket[key-proc], the
497former to lookup the requested key and the latter to extract it.
498
499The @racket[ref-proc] must accept @racket[hash] and a key passed
500to @racket[hash-ref]. It must return a replacement key
501as well as a procedure. The returned procedure is called only if the
502returned key is found in @racket[hash] via @racket[hash-ref], in which
503case the procedure is called with @racket[hash], the previously
504returned key, and the found value. The returned procedure must itself
505return a replacement for the found value. The returned procedure
506is ignored by @racket[hash-ref-key].
507
508The @racket[set-proc] must accept @racket[hash], a key passed to
509@racket[hash-set!] or @racket[hash-set], and the value passed to
510@racket[hash-set!] or @racket[hash-set]; it must produce two values: a
511replacement for the key and a replacement for the value. The returned
512key and value are used with @racket[hash-set!] or @racket[hash-set] on
513the original @racket[hash] to install the value.
514
515The @racket[remove-proc] must accept @racket[hash] and a key passed to
516@racket[hash-remove!] or @racket[hash-remove]; it must produce a
517replacement for the key, which is used with @racket[hash-remove!] or
518@racket[hash-remove] on the original @racket[hash] to remove any
519mapping using the (impersonator-replaced) key.
520
521The @racket[key-proc] must accept @racket[hash] and a key that has
522been extracted from @racket[hash] (by @racket[hash-ref-key],
523@racket[hash-iterate-key], or other operations that use
524@racket[hash-iterate-key] internally); it must produce a replacement
525for the key, which is then reported as a key extracted from the table.
526
527If @racket[clear-proc] is not @racket[#f], it must accept
528@racket[hash] as an argument, and its result is ignored. The fact that
529@racket[clear-proc] returns (as opposed to raising an exception or
530otherwise escaping) grants the capability to remove all keys from @racket[hash].
531If @racket[clear-proc] is @racket[#f], then @racket[hash-clear] or
532@racket[hash-clear!] on the impersonator is implemented using
533@racket[hash-iterate-key] and @racket[hash-remove] or @racket[hash-remove!].
534
535If @racket[equal-key-proc] is not @racket[#f], it effectively
536interposes on calls to @racket[equal?], @racket[equal-hash-code], and
537@racket[equal-secondary-hash-code] for the keys of @racket[hash]. The
538@racket[equal-key-proc] must accept as its arguments @racket[hash] and
539a key that is either mapped by @racket[hash] or passed to
540@racket[hash-ref], etc., where the latter has potentially been
541adjusted by the corresponding @racket[ref-proc], etc@|.__| The result
542is a value that is passed to @racket[equal?],
543@racket[equal-hash-code], and @racket[equal-secondary-hash-code] as
544needed to hash and compare keys. In the case of @racket[hash-set!] or
545@racket[hash-set], the key that is passed to @racket[equal-key-proc]
546is the one stored in the hash table for future lookup.
547
548The @racket[hash-iterate-value], @racket[hash-map], or
549@racket[hash-for-each] functions use a combination of
550@racket[hash-iterate-key] and @racket[hash-ref]. If a key
551produced by @racket[key-proc] does not yield a value through
552@racket[hash-ref], then the @exnraise[exn:fail:contract].
553
554Pairs of @racket[prop] and @racket[prop-val] add impersonator properties
555or override impersonator-property values of @racket[hash].
556
557In the case of an immutable hash table, two impersonated hash tables count as
558``the same value'' (for purposes of @racket[impersonator-of?]) when their
559redirection procedures were originally attached to a hash table by the same
560call to @racket[impersonate-hash] or @racket[chaperone-hash] (and potentially
561propagated by @racket[hash-set], @racket[hash-remove], or @racket[hash-clear]),
562as long as the content of the first hash table is @racket[impersonator-of?] of
563the second hash table.
564
565@history[#:changed "6.3.0.11" @elem{Added the @racket[equal-key-proc]
566                                    argument.}]}
567
568
569@defproc[(impersonate-channel [channel channel?]
570                              [get-proc (channel? . -> . (values channel? (any/c . -> . any/c)))]
571                              [put-proc (channel? any/c . -> . any/c)]
572                              [prop impersonator-property?]
573                              [prop-val any/c] ... ...)
574          (and/c channel? impersonator?)]{
575
576Returns an impersonator of @racket[channel], which redirects the
577@racket[channel-get] and @racket[channel-put] operations.
578
579The @racket[get-proc] generator is called on @racket[channel-get]
580or any other operation that fetches results from the channel (such
581as a @racket[sync] on the channel). The @racket[get-proc] must return
582two values: a @tech{channel} that is an impersonator of @racket[channel], and a
583procedure that is used to check the channel's contents.
584
585The @racket[put-proc] must accept @racket[channel] and the value passed to
586@racket[channel-put]; it must produce a replacement
587value, which is used with @racket[channel-put] on the original
588@racket[channel] to send the value over the channel.
589
590Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
591to @racket[impersonate-channel] must be odd) add impersonator properties
592or override impersonator-property values of @racket[channel].}
593
594
595@defproc[(impersonate-prompt-tag [prompt-tag continuation-prompt-tag?]
596                                 [handle-proc procedure?]
597                                 [abort-proc procedure?]
598                                 [cc-guard-proc procedure? values]
599                                 [callcc-impersonate-proc (procedure? . -> . procedure?) (lambda (p) p)]
600                                 [prop impersonator-property?]
601                                 [prop-val any/c] ... ...)
602          (and/c continuation-prompt-tag? impersonator?)]{
603
604Returns an impersonator of @racket[prompt-tag], which redirects
605the @racket[call-with-continuation-prompt] and
606@racket[abort-current-continuation] operations.
607
608The @racket[handle-proc] must accept the values that the handler
609of a continuation prompt would take and it must produce replacement
610values, which will be passed to the handler.
611
612The @racket[abort-proc] must accept the values passed to
613@racket[abort-current-continuation]; it must produce replacement
614values, which are aborted to the appropriate prompt.
615
616The @racket[cc-guard-proc] must accept the values produced by
617@racket[call-with-continuation-prompt] in the case that a
618non-composable continuation is applied to replace the continuation
619that is delimited by the prompt, but only if
620@racket[abort-current-continuation] is not later used to abort the
621continuation delimited by the prompt (in which case
622@racket[abort-proc] is used).
623
624The @racket[callcc-impersonate-proc] must accept a procedure that
625guards the result of a continuation captured by
626@racket[call-with-current-continuation] with the impersonated prompt
627tag. The @racket[callcc-impersonate-proc] is applied (under a
628@tech{continuation barrier}) when the captured continuation is applied
629to refine a guard function (initially @racket[values]) that is
630specific to the delimiting prompt; this prompt-specific guard is
631ultimately composed with any @racket[cc-guard-proc] that is in effect
632at the delimiting prompt, and it is not used in the same case that a
633@racket[cc-guard-proc] is not used (i.e., when
634@racket[abort-current-continuation] is used to abort to the
635prompt). In the special case where the delimiting prompt at
636application time is a thread's built-in initial prompt,
637@racket[callcc-impersonate-proc] is ignored (partly on the grounds
638that the initial prompt's result is ignored).
639
640Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
641to @racket[impersonate-prompt-tag] must be odd) add impersonator properties
642or override impersonator-property values of @racket[prompt-tag].
643
644@examples[
645  (define tag
646    (impersonate-prompt-tag
647     (make-continuation-prompt-tag)
648     (lambda (n) (* n 2))
649     (lambda (n) (+ n 1))))
650
651  (call-with-continuation-prompt
652    (lambda ()
653      (abort-current-continuation tag 5))
654    tag
655    (lambda (n) n))
656]
657}
658
659
660@defproc[(impersonate-continuation-mark-key
661          [key continuation-mark-key?]
662          [get-proc procedure?]
663          [set-proc procedure?]
664          [prop impersonator-property?]
665          [prop-val any/c] ... ...)
666         (and/c continuation-mark? impersonator?)]{
667
668Returns an impersonator of @racket[key], which redirects
669@racket[with-continuation-mark] and continuation mark accessors such
670as @racket[continuation-mark-set->list].
671
672The @racket[get-proc] must accept the value attached to a
673continuation mark and it must produce a replacement
674value, which will be returned by the continuation mark accessor.
675
676The @racket[set-proc] must accept a value passed to
677@racket[with-continuation-mark]; it must produce a replacement
678value, which is attached to the continuation frame.
679
680Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
681to @racket[impersonate-continuation-mark-key] must be odd) add impersonator properties
682or override impersonator-property values of @racket[key].
683
684@examples[
685  (define mark-key
686    (impersonate-continuation-mark-key
687     (make-continuation-mark-key)
688     (lambda (l) (map char-upcase l))
689     (lambda (s) (string->list s))))
690
691  (with-continuation-mark mark-key "quiche"
692    (continuation-mark-set-first
693     (current-continuation-marks)
694     mark-key))
695]
696}
697
698
699@defthing[prop:impersonator-of struct-type-property?]{
700
701A @tech{structure type property} (see @secref["structprops"]) that
702supplies a procedure for extracting an impersonated value from a structure
703that represents an impersonator. The property is used for @racket[impersonator-of?]
704as well as @racket[equal?].
705
706The property value must be a procedure of one argument, which is a
707structure whose structure type has the property. The result can be
708@racket[#f] to indicate the structure does not represent an impersonator,
709otherwise the result is a value for which the original structure is an
710impersonator (so the original structure is an @racket[impersonator-of?] and
711@racket[equal?] to the result value). The result value must have the
712same @racket[prop:impersonator-of] and @racket[prop:equal+hash] property
713values as the original structure, if any, and the property values must be
714inherited from the same structure type (which ensures some consistency
715between @racket[impersonator-of?] and @racket[equal?]).
716
717@tech{Impersonator property} predicates and accessors applied to a
718structure with the @racket[prop:impersonator-of] property first check
719for the property on the immediate structure, and if it is not found,
720the value produced by the @racket[prop:impersonator-of] procedure is
721checked (recursively).
722
723@history[#:changed "6.1.1.8" @elem{Made @tech{impersonator property}
724                                   predicates and accessors sensitive
725                                   to @racket[prop:impersonator-of].}]}
726
727
728@defthing[prop:authentic struct-type-property?]{
729
730A @tech{structure type property} that declares a structure type as
731@deftech{authentic}. The value associated with the property is ignored;
732the presence of the property itself makes the structure type
733authentic.
734
735Instances of an @tech{authentic} structure type cannot be impersonated
736via @racket[impersonate-struct] or chaperoned via
737@racket[chaperone-struct]. As a consequence, an instance of an
738@tech{authentic} structure type can be given a contract (see
739@racket[struct/c]) only if it is a @tech{flat contract}.
740
741Declaring a structure type as @tech{authentic} can prevent unwanted
742structure impersonation, but exposed structure types normally should
743support impersonators or chaperones to facilitate contracts. Declaring
744a structure type as @tech{authentic} can also slightly improve the
745performance of structure predicates, selectors, and mutators, which
746can be appropriate for data structures that are private
747and frequently used within a library.
748
749@history[#:added "6.9.0.4"]}
750
751@; ------------------------------------------------------------
752@section{Chaperone Constructors}
753
754@defproc[(chaperone-procedure [proc procedure?]
755                              [wrapper-proc (or/c procedure? #f)]
756                              [prop impersonator-property?]
757                              [prop-val any/c] ... ...)
758         (and/c procedure? chaperone?)]{
759
760Like @racket[impersonate-procedure], but for each value supplied to
761@racket[wrapper-proc], the corresponding result must be the same or a
762chaperone of (in the sense of @racket[chaperone-of?])  the supplied
763value. The additional result, if any, that precedes the chaperoned
764values must be a procedure that accepts as many results as produced by
765@racket[proc]; it must return the same number of results, each of
766which is the same or a chaperone of the corresponding original result.
767
768For applications that include keyword arguments, @racket[wrapper-proc]
769must return an additional value before any other values but after the
770result-chaperoning procedure (if any). The additional value must be a
771list of chaperones of the keyword arguments that were supplied to the
772chaperone procedure (i.e., not counting optional arguments that were
773not supplied). The arguments must be ordered according to the sorted
774order of the supplied arguments' keywords.}
775
776
777@defproc[(chaperone-procedure* [proc procedure?]
778                               [wrapper-proc (or/c procedure? #f)]
779                               [prop impersonator-property?]
780                               [prop-val any/c] ... ...)
781         (and/c procedure? chaperone?)]{
782
783Like @racket[chaperone-procedure], but @racket[wrapper-proc] receives
784an extra argument as with @racket[impersonate-procedure*].
785
786@history[#:added "6.1.1.5"]}
787
788
789@defproc[(chaperone-struct [v any/c]
790                           [struct-type struct-type? _unspecified]
791                           [orig-proc (or/c struct-accessor-procedure?
792                                            struct-mutator-procedure?
793                                            struct-type-property-accessor-procedure?
794                                            (one-of/c struct-info))]
795                           [redirect-proc (or/c procedure? #f)] ... ...
796                           [prop impersonator-property?]
797                           [prop-val any/c] ... ...)
798          any/c]{
799
800Like @racket[impersonate-struct], but with the following refinements,
801where @racket[_self] refers to the value to which
802a @racket[orig-proc] is originally applied:
803
804@itemlist[
805
806 @item{With a structure-field accessor as @racket[orig-proc],
807      @racket[redirect-proc] must accept two arguments, @racket[_self] and
808      the value @racket[_field-v] that @racket[orig-proc] produces for
809      @racket[v]; it must return a chaperone of @racket[_field-v]. The
810      corresponding field may be immutable.}
811
812 @item{With structure-field mutator as @racket[orig-proc],
813      @racket[redirect-proc] must accept two arguments, @racket[_self] and
814      the value @racket[_field-v] supplied to the mutator; it must
815      return a chaperone of @racket[_field-v] to be propagated to
816      @racket[orig-proc] and @racket[v].}
817
818 @item{A property accessor can be supplied as @racket[orig-proc], and
819       the property need not have been created with
820       @racket['can-impersonate].  The corresponding
821       @racket[redirect-proc] uses the same protocol as for a
822       structure-field accessor.}
823
824 @item{With @racket[struct-info] as @racket[orig-proc], the
825       corresponding @racket[redirect-proc] must accept two values,
826       which are the results of @racket[struct-info] on @racket[v]; it
827       must return each values or a chaperone of each value. The
828       @racket[redirect-proc] is not called if @racket[struct-info]
829       would return @racket[#f] as its first argument. An
830       @racket[orig-proc] can be @racket[struct-info] only if
831       @racket[struct-type] or some other @racket[orig-proc] is supplied.}
832
833 @item{Any accessor or mutator @racket[orig-proc] that is an
834       @tech{impersonator} must be specifically a @tech{chaperone}.}
835
836]
837
838Supplying a property accessor for @racket[orig-proc] enables
839@racket[prop] arguments, the same as supplying an accessor, mutator,
840or structure type.
841
842@history[#:changed "6.1.1.2" @elem{Changed first argument to an
843                                   accessor or mutator
844                                   @racket[redirect-proc] from
845                                   @racket[v] to @racket[_self].}
846         #:changed "6.1.1.8" @elem{Added optional @racket[struct-type]
847                                   argument.}]}
848
849@defproc[(chaperone-vector [vec vector?]
850                           [ref-proc (or/c (vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
851                           [set-proc (or/c (vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
852                           [prop impersonator-property?]
853                           [prop-val any/c] ... ...)
854          (and/c vector? chaperone?)]{
855
856Like @racket[impersonate-vector], but with support for immutable vectors. The
857@racket[ref-proc] procedure must produce the same value or a chaperone
858of the original value, and @racket[set-proc] must produce the value
859that is given or a chaperone of the value. The @racket[set-proc] will
860not be used if @racket[vec] is immutable.}
861
862@defproc[(chaperone-vector* [vec (and/c vector? (not/c immutable?))]
863                            [ref-proc (or/c (vector? vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
864                            [set-proc (or/c (vector? vector? exact-nonnegative-integer? any/c . -> . any/c) #f)]
865                            [prop impersonator-property?]
866                            [prop-val any/c] ... ...)
867         (and/c vector? chaperone?)]{
868 Like @racket[chaperone-vector], but @racket[ref-proc] and @racket[set-proc] receive an extra argument
869 as with @racket[impersonate-vector*].
870
871 @history[#:added "6.9.0.2"]
872}
873
874@defproc[(chaperone-box [box box?]
875                        [unbox-proc (box? any/c . -> . any/c)]
876                        [set-proc (box? any/c . -> . any/c)]
877                        [prop impersonator-property?]
878                        [prop-val any/c] ... ...)
879          (and/c box? chaperone?)]{
880
881Like @racket[impersonate-box], but with support for immutable boxes. The
882@racket[unbox-proc] procedure must produce the same value or a
883chaperone of the original value, and @racket[set-proc] must produce
884the same value or a chaperone of the value that it is given.  The
885@racket[set-proc] will not be used if @racket[box] is immutable.}
886
887
888@defproc[(chaperone-hash [hash hash?]
889                         [ref-proc (hash? any/c . -> . (values
890                                                        any/c
891                                                        (hash? any/c any/c . -> . any/c)))]
892                         [set-proc (hash? any/c any/c . -> . (values any/c any/c))]
893                         [remove-proc (hash? any/c . -> . any/c)]
894                         [key-proc (hash? any/c . -> . any/c)]
895                         [clear-proc (or/c #f (hash? . -> . any)) #f]
896                         [equal-key-proc (or/c #f (hash? any/c . -> . any/c)) #f]
897                         [prop impersonator-property?]
898                         [prop-val any/c] ... ...)
899          (and/c hash? chaperone?)]{
900
901Like @racket[impersonate-hash], but with constraints on the given functions
902and support for immutable hashes. The @racket[ref-proc] procedure must
903return a found value or a chaperone of the value. The
904@racket[set-proc] procedure must produce two values: the key that it
905is given or a chaperone of the key and the value that it is given or a
906chaperone of the value. The @racket[remove-proc], @racket[key-proc],
907and @racket[equal-key-proc]
908procedures must produce the given key or a chaperone of the key.
909
910@history[#:changed "6.3.0.11" @elem{Added the @racket[equal-key-proc]
911                                    argument.}]}
912
913@defproc[(chaperone-struct-type [struct-type struct-type?]
914                                [struct-info-proc procedure?]
915                                [make-constructor-proc (procedure? . -> . procedure?)]
916                                [guard-proc procedure?]
917                                [prop impersonator-property?]
918                                [prop-val any/c] ... ...)
919          (and/c struct-type? chaperone?)]{
920
921Returns a chaperoned value like @racket[struct-type], but with
922@racket[struct-type-info] and @racket[struct-type-make-constructor]
923operations on the chaperoned structure type redirected. In addition,
924when a new structure type is created as a subtype of the chaperoned
925structure type, @racket[guard-proc] is interposed as an extra guard on
926creation of instances of the subtype.
927
928The @racket[struct-info-proc] must accept 8 arguments---the result of
929@racket[struct-type-info] on @racket[struct-type]. It must return 8
930values, where each is the same or a chaperone of the corresponding
931argument. The 8 values are used as the results of
932@racket[struct-type-info] for the chaperoned structure type.
933
934The @racket[make-constructor-proc] must accept a single procedure
935argument, which is a constructor produced by
936@racket[struct-type-make-constructor] on @racket[struct-type]. It must
937return the same or a chaperone of the procedure, which is used as the
938result of @racket[struct-type-make-constructor] on the chaperoned
939structure type.
940
941The @racket[guard-proc] is like a @racket[guard] argument to
942@racket[make-struct-type]: it must accept one more argument
943than a constructor for @racket[struct-type], where the last argument
944is the name the name of the instantiated structure type.
945It must return the number of values needed by the constructor
946(i.e. one value for each argument but the last),
947and each returned value must be the same as
948or a chaperone of the corresponding argument.
949The @racket[guard-proc] is added as a constructor guard when a subtype is
950created of the chaperoned structure type.
951
952Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
953to @racket[chaperone-struct-type] must be even) add impersonator properties
954or override impersonator-property values of @racket[struct-type].}
955
956@defproc[(chaperone-evt [evt evt?]
957                        [proc (evt? . -> . (values evt? (any/c . -> . any/c)))]
958                        [prop impersonator-property?]
959                        [prop-val any/c] ... ...)
960          (and/c evt? chaperone?)]{
961
962Returns a chaperoned value like @racket[evt], but with @racket[proc]
963as an event generator when the result is synchronized with functions
964like @racket[sync].
965
966The @racket[proc] generator is called on synchronization, much like
967the procedure passed to @racket[guard-evt], except that @racket[proc]
968is given @racket[evt]. The @racket[proc] must return two values: a
969@tech{synchronizable event} that is a chaperone of @racket[evt], and a
970procedure that is used to check the event's result if it is chosen in
971a selection. The latter procedure accepts the result of @racket[evt],
972and it must return a chaperone of that value.
973
974Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
975to @racket[chaperone-evt] must be even) add impersonator properties
976or override impersonator-property values of @racket[evt].
977
978The result is @racket[chaperone-of?] the argument @racket[evt].
979However, if @racket[evt] is a @tech{thread}, @tech{semaphore},
980@tech{input port}, @tech{output port}, or @tech{will executor}, the
981result is not recognized as such. For example, @racket[thread?]
982applied to the result of @racket[chaperone-evt] will always produce
983@racket[#f].}
984
985
986@defproc[(chaperone-channel [channel channel?]
987                            [get-proc (channel? . -> . (values channel? (any/c . -> . any/c)))]
988                            [put-proc (channel? any/c . -> . any/c)]
989                            [prop impersonator-property?]
990                            [prop-val any/c] ... ...)
991          (and/c channel? chaperone?)]{
992
993Like @racket[impersonate-channel], but with restrictions on the
994@racket[get-proc] and @racket[put-proc] procedures.
995
996The @racket[get-proc] must return two values: a @tech{channel}
997that is a chaperone of @racket[channel], and a procedure that
998is used to check the channel's contents. The latter procedure
999must return the original value or a chaperone of that value.
1000
1001The @racket[put-proc] must produce a replacement value that is
1002either the original value communicated on the channel or a
1003chaperone of that value.
1004
1005Pairs of @racket[prop] and @racket[prop-val] (the number of arguments
1006to @racket[chaperone-channel] must be odd) add impersonator properties
1007or override impersonator-property values of @racket[channel].}
1008
1009
1010@defproc[(chaperone-prompt-tag [prompt-tag continuation-prompt-tag?]
1011                               [handle-proc procedure?]
1012                               [abort-proc procedure?]
1013                               [cc-guard-proc procedure? values]
1014                               [callcc-chaperone-proc (procedure? . -> . procedure?) (lambda (p) p)]
1015                               [prop impersonator-property?]
1016                               [prop-val any/c] ... ...)
1017          (and/c continuation-prompt-tag? chaperone?)]{
1018
1019Like @racket[impersonate-prompt-tag], but produces a chaperoned value.
1020The @racket[handle-proc] procedure must produce the same values or
1021chaperones of the original values, @racket[abort-proc] must produce
1022the same values or chaperones of the values that it is given, and
1023@racket[cc-guard-proc] must produce the same values or chaperones of
1024the original result values, and @racket[callcc-chaperone-proc] must
1025produce a procedure that is a chaperone or the same as the given
1026procedure.
1027
1028@examples[
1029  (define bad-chaperone
1030    (chaperone-prompt-tag
1031     (make-continuation-prompt-tag)
1032     (lambda (n) (* n 2))
1033     (lambda (n) (+ n 1))))
1034
1035  (eval:error
1036   (call-with-continuation-prompt
1037     (lambda ()
1038       (abort-current-continuation bad-chaperone 5))
1039     bad-chaperone
1040     (lambda (n) n)))
1041
1042  (define good-chaperone
1043    (chaperone-prompt-tag
1044     (make-continuation-prompt-tag)
1045     (lambda (n) (if (even? n) n (error "not even")))
1046     (lambda (n) (if (even? n) n (error "not even")))))
1047
1048  (call-with-continuation-prompt
1049    (lambda ()
1050      (abort-current-continuation good-chaperone 2))
1051    good-chaperone
1052    (lambda (n) n))
1053]
1054}
1055
1056
1057@defproc[(chaperone-continuation-mark-key
1058          [key continuation-mark-key?]
1059          [get-proc procedure?]
1060          [set-proc procedure?]
1061          [prop impersonator-property?]
1062          [prop-val any/c] ... ...)
1063         (and/c continuation-mark-key? chaperone?)]{
1064
1065Like @racket[impersonate-continuation-mark-key], but produces a
1066chaperoned value.  The @racket[get-proc] procedure must produce the
1067same value or a chaperone of the original value, and @racket[set-proc]
1068must produce the same value or a chaperone of the value that it is
1069given.
1070
1071@examples[
1072  (define bad-chaperone
1073    (chaperone-continuation-mark-key
1074     (make-continuation-mark-key)
1075     (lambda (l) (map char-upcase l))
1076     string->list))
1077
1078  (eval:error
1079   (with-continuation-mark bad-chaperone "timballo"
1080     (continuation-mark-set-first
1081      (current-continuation-marks)
1082      bad-chaperone)))
1083
1084  (define (checker s)
1085    (if (> (string-length s) 5)
1086        s
1087        (error "expected string of length at least 5")))
1088
1089  (define good-chaperone
1090    (chaperone-continuation-mark-key
1091     (make-continuation-mark-key)
1092     checker
1093     checker))
1094
1095  (with-continuation-mark good-chaperone "zabaione"
1096    (continuation-mark-set-first
1097     (current-continuation-marks)
1098     good-chaperone))
1099]
1100}
1101
1102@; ------------------------------------------------------------
1103@section{Impersonator Properties}
1104
1105@defproc[(make-impersonator-property [name symbol?])
1106         (values impersonator-property?
1107                 (-> any/c boolean?)
1108                 (->* (impersonator?) (any/c) any))]{
1109
1110Creates a new @tech{impersonator property} and returns three values:
1111
1112@itemize[
1113
1114 @item{an @deftech{impersonator property descriptor}, for use with
1115       @racket[impersonate-procedure], @racket[chaperone-procedure],
1116       and other impersonator constructors;}
1117
1118 @item{an @deftech{impersonator property predicate} procedure, which takes
1119       an arbitrary value and returns @racket[#t] if the value is an
1120       impersonator with a value for the property, @racket[#f]
1121       otherwise;}
1122
1123 @item{an @deftech{impersonator property accessor} procedure, which
1124       returns the value associated with an impersonator for the property;
1125       if a value given to the accessor is not an impersonator or does not
1126       have a value for the property (i.e. if the corresponding impersonator
1127       property predicate returns @racket[#f]), then a second optional argument
1128       to the selector determines its response: the @exnraise[exn:fail:contract]
1129       if a second argument is not provided, the second argument is tail-called
1130       with zero arguments if it is a procedure, and the second argument is returned
1131       otherwise.}
1132
1133]}
1134
1135@defproc[(impersonator-property? [v any/c]) boolean?]{
1136
1137Returns @racket[#t] if @racket[v] is a @tech{impersonator property
1138descriptor} value, @racket[#f] otherwise.}
1139
1140@defproc[(impersonator-property-accessor-procedure? [v any/c]) boolean?]{
1141
1142Returns @racket[#t] if @racket[v] is an accessor procedure produced
1143by @racket[make-impersonator-property], @racket[#f] otherwise.}
1144
1145
1146@defthing[impersonator-prop:application-mark impersonator-property?]{
1147
1148An @tech{impersonator property} that is recognized by @racket[impersonate-procedure]
1149and @racket[chaperone-procedure].}
1150
1151