#
Chapter 4
Structures

A structure type is a record datatype composing a number of fields. A structure, an instance of a structure type, is a first-class value that contains a value for each field of the structure type. A structure instance is created with a type-specific constructor procedure, and its field values are accessed and changed with type-specific selector and setter procedures. In addition, each structure type has a predicate procedure that answers `#t` for instances of the structure type and `#f` for any other value.

## 4.1 Defining Structure Types

A new structure type can be created with one of four `define-struct` forms:

    (define-struct s (field ···) [inspector-expr])
    (define-struct (s t) (field ···) [inspector-expr])

where `s`, `t`, and each `field` are identifiers. The latter form is described in section 4.2. The optional `inspector-expr` is explained in section 4.5.

A `define-struct` expression with `n` `field`s defines 4 + 2n names:

- `struct:``s`, a structure type descriptor value that represents the new datatype. This value is rarely used directly.

- `make-``s`, a constructor procedure that takes `n` arguments and returns a new structure value.

- `s``?`, a predicate procedure that returns `#t` for a value constructed by `make-``s` (or the constructor for a subtype; see section 4.2) and `#f` for any other value.

- `s``-``field`, for each `field`, an accessor procedure that takes a structure value and extracts the value for `field`.

- `set-``s``-``field``!`, for each `field`, a mutator procedure that takes a structure and a new field value. The field value in the structure is destructively updated with the new value, and void is returned.

- `s`, a syntax binding that encapsulates information about the structure type declaration. This binding is used to define subtypes (see section 4.2). It also works with the `shared` and `match` forms (see Chapter mz:mzlibshared and Chapter mz:mzlibmatch in PLT MzLib: Libraries Manual). For detailed information about the expansion-time information stored in `s`, see section 12.6.3.

Each time a `define-struct` expression is evaluated, a new structure type is created with distinct constructor, predicate, accessor, and mutator procedures. If the same `define-struct` expression is evaluated twice, instances created by the constructor returned by the first evaluation will answer `#f` to the predicate returned by the second evaluation.

Examples:

    (define-struct cons-cell (car cdr))
    (define x (make-cons-cell 1 2))
    (cons-cell? x) ; => #t
    (cons-cell-car x) ; => 1
    (set-cons-cell-car! x 5)
    (cons-cell-car x) ; => 5

    (define orig-cons-cell? cons-cell?)
    (define-struct cons-cell (car cdr))
    (define y (make-cons-cell 1 2))
    (cons-cell? y) ; => #t
    (cons-cell? x) ; => #f, cons-cell? now checks for a different type
    (orig-cons-cell? x) ; => #t
    (orig-cons-cell? y) ; => #f

The `let-struct` form binds structure identifiers in a lexical scope; it does not support an `inspector-expr`.

    (let-struct s (field ···)
      body-expr ···1)
    (let-struct (s t) (field ···)
      body-expr ···1)

## 4.2 Creating Subtypes

The latter `define-struct` form shown in section 4.1 creates a new structure type that is a structure subtype of an existing base structure type. An instance of a structure subtype can always be used as an instance of the base structure type, but the subtype gets its own predicate procedure and may have its own fields in addition to the fields of the base type.

The `t` identifier in a subtyping `define-struct` form must be bound to syntax describing a structure type declaration. Normally, it is the name of a structure type previously declared with `define-struct`. The information associated with `t` is used to access the base structure type for the new subtype.

A structure subtype ``inherits'' the fields of its base type. If the base type has `m` fields, and if `n` fields are specified in the subtyping `define-struct` expression, then the resulting structure type has m + n fields. Consequently, m + n field values must be provided to the subtype's constructor procedure. Values for the first `m` fields of a subtype instance are accessed with selector procedures for the original base type, and the last `n` are accessed with subtype-specific selectors. Subtype-specific accessors and mutators for the first `m` fields are not created.

Examples:

    (define-struct cons-cell (car cdr))
    (define x (make-cons-cell 1 2))
    (define-struct (tagged-cons-cell cons-cell) (tag))
    (define z (make-tagged-cons-cell 3 4 't))
    (cons-cell? z) ; => #t
    (tagged-cons-cell? z) ; => #t
    (tagged-cons-cell? x) ; => #f
    (cons-cell-car z) ; => 3
    (tagged-cons-cell-tag z) ; => 't

## 4.3 Structure Types with Automatic Fields, Immutable Fields, and Properties

The ``make-struct-type`` procedure creates a new structure type in the same way as the `define-struct` form of section 4.1, but provides a more general interface. In particular, the ``make-struct-type`` procedure supports structure type properties.

- `(make-struct-type``` `name-symbol super-struct-type init-field-k auto-field-k``` [`auto-v prop-value-list inspector proc-spec immutable-k-list`]`)` creates a new structure type. The `name-symbol` argument is used as the type name. If `super-struct-type` is not `#f`, the new type is a subtype of the corresponding structure type, as described in section 4.2.

  The new structure type has `init-field-k` + `auto-field-k` fields (in addition to any fields from `super-struct-type`), but only `init-field-k` constructor arguments (in addition to any constructor arguments from `super-struct-type`). The remaining fields are initialized with `auto-v`, which defaults to `#f`.

  The `prop-value-list` argument is a list of pairs, where the ``car`` of each pair is a structure type property descriptor, and the ``cdr`` is an arbitrary value. The default is ``null``. See section 4.4 for more information about properties.

  The `inspector` argument controls access to debugging information about the structure type and its instances; see section 4.5 for more information.

  The `proc-spec` argument can be `#f`, an exact non-negative integer, or a procedure. The default is `#f`. If an integer or procedure is provided, instances of the structure type act as procedures. See section 4.6 for further information.

  The `immutable-k-list` argument provides a list of exact, non-negative integers that identify immutable field positions. Each element in the list should be unique, otherwise `exn:application:mismatch` exception is raised. Each element should also fall in the range `0` (inclusive) and `init-field-k` (exclusive), otherwise `exn:application:mismatch` exception is raised.

  The result of `make-struct-type` is five values, which are similar to the values produced by `define-struct` (see section 4.1):

  - a structure type descriptor,

  - a constructor procedure,

  - a predicate procedure,

  - an accessor procedure, which consumes a structure and a field index between 0 (inclusive) and `init-field-k` + `auto-field-k` (exclusive), and

  - a mutator procedure, which consumes a structure, a field index, and a field value.

Unlike `define-struct`, ``make-struct-type`` returns a single accessor procedure and a single mutator procedure for all fields. The ``make-struct-field-accessor`` and ``make-struct-field-mutator`` procedures convert a type-specific accessor or mutator returned by ``make-struct-type`` into a field-specific accessor or mutator:

- `(make-struct-field-accessor``` `accessor-proc field-pos-k field-name-symbol``)` returns a field accessor that is equivalent to

       (lambda (s) (accessor-proc s field-pos-k))

  The `accessor-proc` must be an accessor returned by ``make-struct-type``. The name of the resulting procedure for debugging purposes is derived from `field-name-symbol` and the name of `accessor-proc`'s structure type.

- `(make-struct-field-mutator``` `mutator-proc field-pos-k field-name-symbol``)` returns a field mutator that is equivalent to

       (lambda (s v) (mutator-proc s field-pos-k v))

  The `mutator-proc` must be a mutator returned by ``make-struct-type``. The name of the resulting procedure for debugging purposes is derived from `field-name-symbol` and the name of `mutator-proc`'s structure type.

Examples:

    (define-values (struct:a make-a a? a-ref a-set!)
      (make-struct-type 'a #f 2 1 'uninitialized))
    (define an-a (make-a 'x 'y))
    (a-ref an-a 1) ; => 'y
    (a-ref an-a 2) ; => 'uninitialized
    (define a-first (make-struct-field-accessor a-ref 0))
    (a-first an-a) ; => 'x

## 4.4 Structure Type Properties

A structure type property allows per-type information to be associated with a structure type (as opposed to per-instance information associated with a structure value). A property value is associated with a structure type through the ``make-struct-type`` procedure (see section 4.3). Subtypes inherit the property values of their parent types, and only one value can be associated with a type for any property.

`(make-struct-type-property``` `name-symbol``` [`guard-proc`]`)` creates a new structure type property and returns three values:

- a structure property type descriptor, for use with ``make-struct-type``;

- a predicate procedure, which takes an arbitrary value and returns `#t` if the value is a descriptor or instance of a structure type that has a value for the property, `#f` otherwise;

- an accessor procedure, which returns the value associated with structure type given its descriptor or one of its instances; the structure type does not have a value for the property, or if any other kind of value is provided, the `exn:application:type` exception is raised.

If the optional `guard-proc` is supplied, it is called by ``make-struct-type`` before attaching the property to a new structure type. The `guard-proc` must accept to arguments: a value for the property supplied to ``make-struct-type``, and a list containing information about the new structure type. The list contains the values that `struct-type-info` would return for the new structure type if it skipped the current-inspector control check (see section 4.5).

The result of calling `guard-proc` is associated with the property in the target structure type, instead of the vale supplied to ``make-struct-type``. To reject a property association (e.g., because the value supplied to ``make-struct-type`` is inappopriate for the property), the guard can raise an exception. Such an exception prevents ``make-struct-type`` from returning a structure type descriptor.

`(struct-type-property?``` `v``)` returns `#t` if `v` is a structure type property descriptor value, `#f` otherwise.

Examples:

    (define-values (prop:p p? p-ref) (make-struct-type-property 'p))

    (define-values (struct:a make-a a? a-ref a-set!)
      (make-struct-type 'a #f 2 1 'uninitialized (list (cons prop:p 8))))
    (p? struct:a) ; => #t
    (p? 13) ; => #f
    (define an-a (make-a 'x 'y))
    (p? an-a) ; => #t
    (p-ref an-a) ; => 8

    (define-values (struct:b make-b b? b-ref b-set!)
      (make-struct-type 'b #f 0 0 #f))
    (p? struct:b) ; => #f

## 4.5 Structure Inspectors

An inspector provides access to structure fields and structure type information without the normal field accessors and mutators. Inspectors are primarily intended for use by debuggers.

When a structure type is created, an inspector can be supplied. The given inspector is not the one that will control the new structure type; instead, the given inspector's parent will control the type. By using the parent of the given inspector, the structure type remains opaque to ``peer'' code that cannot access the parent inspector. Thus, an expression of the form

    (define-struct s (field ···))

creates a structure type whose instances are opaque to peer code. In contrast, the following idiom creates a structure type that is transparent to peer code, because the supplied inspector is a newly created child of the current inspector:

    (define-struct s (field ···) (make-inspector))

The ``current-inspector`` parameter determines a default inspector argument for new structure types. An alternate inspector can be provided though the optional `inspector-expr` expression of the `define-struct` form (see section 4.1), as shown above, or through an optional `inspector` argument to ``make-struct-type`` (see section 4.3).

`(make-inspector``` [`inspector`]`)` returns a new inspector that is a subinspector of `inspector`. If `inspector` is not provided, the new inspector is a subinspector of the current inspector. Any structure type controlled by the new inspector is also controlled by its ancestor inspectors, but no other inspectors.

`(inspector?``` `v``)` returns `#t` if `v` is an inspector, `#f` otherwise.

The ``struct-info`` and ``struct-type-info`` procedures provide inspector-based access to structure and structure type information:

- `(struct-info``` `v``)` returns two values:

  - `struct-type`: a structure type descriptor or `#f`; the result is a structure type descriptor of the most specific type for which `v` is an instance, and for which the current inspector has control, or the result is `#f` if the current inspector does not control any structure type for which the `struct` is an instance.

  - `skipped?`: `#f` if the first result corresponds to the most specific structure type of `v`, `#t` otherwise.

- `(struct-type-info``` `struct-type``)` returns eight values that provide information about the structure type descriptor `struct-type`, assuming that the type is controlled by the current inspector:

  - `name-symbol`: the structure type's name as a symbol;

  - `init-field-k`: the number of fields defined by the structure type provided to the constructor procedure (not counting fields created by its ancestor types);

  - `auto-field-k`: the number of fields defined by the structure type without a conuterpart in the constrcutor procedure (not counting fields created by its ancestor types);

  - `accessor-proc`: an accessor procedure for the structure type, like the one returned by ``make-struct-type``;

  - `mutator-proc`: a mutator procedure for the structure type, like the one returned by ``make-struct-type``;

  - `immutable-k-list`: an immutable list of exact non-negative integers that correspond to immutable fields for the structure type;

  - `super-struct-type`: a structure type descriptor for the most specific ancestor of the type that is controlled by the current inspector, or `#f` if no ancestor is controlled by the current inspector;

  - `skipped?`: `#f` if the sixth result is the most specific ancestor type or if the type has no supertype, `#t` otherwise.

  If the type for `struct-type` is not controlled by the current inspector, the `exn:application:mismatch` exception is raised.

## 4.6 Structures as Procedures

If an integer or procedure is provided as the `proc-spec` argument to `make-struct-type` (see section 4.3), instances of the new structure type are procedures. In particular, when `procedure?` is applied to the instance, the result will be `#t`. When an instance is used in the function position of an application expression, a procedure is extracted from the instance and used to complete the procedure call.

If `proc-spec` is an integer, it designates a field within the structure that should contain a procedure. The `proc-spec` integer must be between 0 (inclusive) and `init-field-k` (exclusive). The designated field becomes immutable, so that after an instance of the structure is created, its procedure cannot be changed. (Otherwise, the arity and name of the instance could change, and such mutations are generally not allowed for procedures.) When the instance is used as the procedure in an application expression, the value of the designated field in the instance is used to complete the procedure call.6 That procedure receives all of the arguments from the application expression. The procedure's name (see section 6.2.4) and arity (see section 3.10.1) are also used for the name and arity of the structure. If the value in the designated field is not a procedure, then the instance behaves like `(case-lambda)` (i.e., a procedure which does not accept any number of arguments).

Example:

    (define-values (struct:ap make-annotated-proc annotated-proc? ap-ref ap-set!)
      (make-struct-type 'anotated-proc #f 2 0 #f null #f 0))
    (define (proc-annotation p) (ap-ref p 1))
    (define plus1 (make-annotated-proc
                    (lambda (x) (+ x 1))
                    "adds 1 to its argument"))
    (procedure? plus1) ; => #t
    (annotated-proc? plus1) ; => #t
    (plus1 10) ; => 11
    (proc-annotation plus1) ; => "adds 1 to its argument"

If `proc-spec` is a procedure, it should accept at least one argument. When an instance of the structure is used in an application expression, the `proc-spec` procedure is called with the instance as the first argument. The remaining arguments to the `proc-spec` procedure are the arguments from the application expression. Thus, if the application expression contained five arguments, `proc-spec` is called with six arguments. The name of the instance (see section 6.2.4) is unaffected by `proc-spec`, but the instance's arity is determined by subtracting one from every possible argument count of `proc-spec`. If `proc-spec` cannot accept at least one argument, then the instance behaves like `(case-lambda)`.

    (define-values (struct:fish make-fish fish? fish-ref fish-set!)
      (make-struct-type 'fish #f 2 0 #f null #f
                        (lambda (f n) (fish-set! f 0 (+ n (fish-ref f 0))))))
    (define (fish-weight f) (fish-ref f 0))
    (define (fish-color f) (fish-ref f 1))
    (define wanda (make-fish 12 'red))
    (fish? wanda) ; => #t
    (procedure? wanda) ; => #t
    (fish-weight wanda) ; => 12
    (for-each wanda '(1 2 3))
    (fish-weight wanda) ; => 18

If a structure type generates procedure instances, then subtypes of the type also generate procedure instances. The instances behave the same as instances of the original type. When a `proc-spec` is supplied with a supertype that already behaves as a procedure, the `exn;application:mismatch` exception is raised.

## 4.7 Structures as Waitable Objects

The built-in `prop:waitable` structure type property identifies structure types whose instances can serve as waitable objects; see section 7.6 for information on waitable objects.

The property value can be any of the following:

- A waitable object `waitable`: In this case, using the structure as a waitable is equivalent to using `waitable`.

- A procedure `proc` of one argument: In this case, the structure is similar to a waitable generated by `make-guard-waitable`, except that the would-be guard procedure `proc` receives the structure as an argument, instead of no arguments.

- An exact, non-negative integer between `0` (inclusive) and `init-field-k` (exclusive): The integer identifies a field in the structure. If the field contains a waitable object or a waitable-generating procedure of one argument, the waitable or procedure is used as above. Otherwise, then the structure acts as a permanently blocked waitable.

Examples:

    (define-values (struct:wt make-wt wt? wt-ref wt-set!)
      (make-struct-type 'wt #f 2 0 #f (list (cons prop:waitable 0)) #f #f '(0)))

    (define sema (make-semaphore))
    (object-wait-multiple 0 (make-wt sema #f)) ; => #f
    (semaphore-post sema)
    (object-wait-multiple 0 (make-wt sema #f)) ; => sema
    (semaphore-post sema)
    (object-wait-multiple 0 (make-wt (lambda (self) (wt-ref self 1)) sema)) ; => sema
    (semaphore-post sema)
    (define my-wt (make-wt (lambda (self) (make-wrapped-waitable
    				       (wt-ref self 1)
    				       (lambda (x) self)))
    		       sema))
    (object-wait-multiple 0 my-wt) ; => my-wt
    (object-wait-multiple 0 my-wt) ; => #f

## 4.8 Structure Utilities

The following utility procedures work on all structure instances:

- `(struct->vector``` `v``` [`opaque-v`]`)` creates a vector representing `v`. The first slot of the result vector contains a symbol of the form `struct:`s``. The each remaining slot contains either the value of a field in `v` if it is accessible via the current inspector, or `opaque-v` for a field that is not accessible. A single `opaque-v` value is used in the vector for contiguous inaccessible fields. (Consequently, the size of the vector does not match the size of the `struct` if more than one field is inaccessible.) The symbol `'...` is the default value for `opaque-v`.

- `(struct?``` `v``)` returns `#t` if `struct->vector` exposes any fields of `v` with the current inspector, `#f` otherwise.

Two structure values are `eqv?` if and only if they are `eq?`. Two structure values are `equal?` if and only if they are instances of the same structure type, no fields are opaque, and the results of applying ``struct->vector`` to the structs are ``equal?``. (Consequently, ``equal?`` testing for structures depends on the current inspector.)

Each kind of value returned by `define-struct` and ``make-struct-type`` has a recognizing predicate:

- `(struct-type?``` `v``)` returns `#t` if `v` is a structure type descriptor value, `#f` otherwise.

- `(struct-constructor-procedure?``` `v``)` returns `#t` if `v` is a constructor procedure generated by `define-struct` or ``make-struct-type``, `#f` otherwise.

- `(struct-predicate-procedure?``` `v``)` returns `#t` if `v` is a predicate procedure generated by `define-struct` or ``make-struct-type``, `#f` otherwise.

- `(struct-accessor-procedure?``` `v``)` returns `#t` if `v` is an accessor procedure generated by `define-struct`, ``make-struct-type``, or ``make-struct-field-accessor``, `#f` otherwise.

- `(struct-mutator-procedure?``` `v``)` returns `#t` if `v` is a mutator procedure generated by `define-struct`, ``make-struct-type``, or ``make-struct-field-mutator``, `#f` otherwise.

6 This procedure can be another structure that acts as a procedure. The immutability of procedure fields disallows cycles in the procedure graph, so that the procedure call will eventually continue with a non-structure procedure.