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