# New struct++ feature: accessor wrappers

**URL:** <https://racket.discourse.group/t/new-struct-feature-accessor-wrappers/1006>\
**Category:** Show & Tell\
**Created:** [May 19, 2022, 4:17pm UTC](https://racket.discourse.group/t/new-struct-feature-accessor-wrappers/1006 "2022-05-19T16:17:07Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [May 19, 2022, 4:17pm UTC](https://racket.discourse.group/t/new-struct-feature-accessor-wrappers/1006/1 "2022-05-19T16:17:07Z")

</div>

Accessor wrappers allow you to redirect a struct accessor to do whatever you want. Good examples would be to force a promise or access a database.

```scheme
#lang racket

(require struct-plus-plus "db/dbh.rkt") ; dbh.rkt provides (dbh) which returns a pre-initialized database connection

(struct++ dog ([name (or/c string? promise?) #:wrap-accessor (wrap-accessor force)]))
(define fido (dog++ #:name (lazy "fido")))
(displayln
 (~a " (dog-name fido), the default struct accessor, returns: " (dog-name fido)
     "\n before dotted accessor, promise was forced?: " (promise-forced? (dog-name fido))
     "\n (dog.name fido), the struct++ dotted accessor, returns: " (dog.name fido)
     "\n after dotted accessor, promise was forced?: " (promise-forced? (dog-name fido))))

; a trivial ORM
(struct++ person ([db-id integer?]
                  [(conn (dbh)) connection?] ; default argument creates the connection
                  [(username #f) string? #:wrap-accessor (lambda (the-person val) (get-username the-person))]
                  [(go-boom #f) integer? #:wrap-accessor (lambda (the-person val) (get-username the-person))]
                  )
          #:transparent)

(define (get-username the-person)
  (query-value (person.conn the-person)
               "select username from users where id = ?"
               (person.db-id the-person)))

(define smith (person++ #:db-id 2))
(displayln (~a "(person.username smith) returns: " (person.username smith)))
(display (~a "(person.go-boom smith) dies because the returned value does not match the field contract: "))
(person.go-boom smith)

```

The output is:

```scheme
 (dog-name fido), the default struct accessor, returns: #<promise!fido>
 before dotted accessor, promise was forced?: #f
 (dog.name fido), the struct++ dotted accessor, returns: fido
 after dotted accessor, promise was forced?: #t
(person.username smith) returns: smith@ursaminor.edu
(person.go-boom smith) dies because the returned value does not match the field contract:
; person.go-boom: broke its own contract                                                                      
; promised: integer?                                                                                        
; produced: "smith@ursaminor.edu"                                                                           
; in: the range of                                                                                          
; (-> person? integer?)                                                                                 
; contract from: (function person.go-boom)                                                                  
; blaming: (function person.go-boom)                                                                        
; (assuming the contract is correct)                                                                       
; at: /Users/dstorrs/test.rkt                                                                  
; Context (plain; to see better errortrace context, re-run with C-u prefix):                                  
; /Applications/Racket_v8.4/collects/racket/contract/private/blame.rkt:346:0 raise-blame-error              
; /Applications/Racket_v8.4/collects/racket/contract/private/arrow-higher-order.rkt:375:33    

```

They come with one caveat which is that they can return a result different from what's actually there, in which case the wrapped accessor would give a different result than you would get from, e.g., `match`.

The fact that the default accessors created by `struct` do not use the wrapper is a feature, not a bug.
