1 Evaluation Model
2 Syntax Model
3 Core Syntactic Forms
4 Core Datatypes
5 Structures
6 Classes and Objects
7 Units
8 Contracts
9 Control Flow
10 Concurrency
11 Macros
12 Input and Output
13 Reflection and Security
14 Operating System
15 Memory Management
16 Running PLT Scheme
Index
On this page:
5.1 Defining Structure Types: define-struct
define-struct
struct-field-index
5.2 Creating Structure Types
make-struct-type
make-struct-field-accessor
make-struct-field-mutator
5.3 Structure Type Properties
make-struct-type-property
struct-type-property?
5.4 Structure Utilities
struct->vector
struct?
struct-type?
struct-constructor-procedure?
struct-predicate-procedure?
struct-accessor-procedure?
struct-mutator-procedure?
5.5 Structure Type Transformer Binding

contents

 index

← prev  up  next →

 

5 Structures

Programmer-Defined Datatypes in A Guide to PLT Scheme introduces structure types via define-struct.

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 accessor and mutator 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.

A structure type’s fields are essentially unnamed, though names are supported for error-reporting purposes. The constructor procedure takes one value for each field of the structure type, except that some of the fields of a structure type can be automatic fields; the automatic fields are initialized to a constant that is associated with the structure type, and the corresponding arguments are omitted for the constructor procedure. All automatic fields in a structure type follow the non-automatic fields.

A structure type can be created as 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 it may have its own fields in addition to the fields of the base type.

A structure subtype “inherits” the fields of its base type. If the base type has m fields, and if n fields are specified for the new structure subtype, then the resulting structure type has m+n fields. The value for automatic fields can be different in a subtype than in its base type.

If m of the original m fields are non-automatic (where m<m), and n of the new fields are automatic (where n<n), then 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 (or its supertypes), and the last n are accessed with subtype-specific selectors. Subtype-specific accessors and mutators for the first m fields do not exist.

Two structure values are eqv? if and only if they are eq?. Two structure values are equal? if they are eq?, or 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.)

5.1 Defining Structure Types: define-struct

Programmer-Defined Datatypes in A Guide to PLT Scheme introduces define-struct.

(define-struct id-maybe-super (field ...)

               struct-option ...)

 

id-maybe-super

 

=

 

id

 

 

|

 

(id super-id)

 

 

 

 

 

field

 

=

 

field-id

 

 

|

 

[field-id field-option ...]

 

 

 

 

 

struct-option

 

=

 

#:immutable

 

 

|

 

#:super super-expr

 

 

|

 

#:inspector inspector-expr

 

 

|

 

#:auto-value auto-expr

 

 

|

 

#:guard guard-expr

 

 

|

 

#:property prop-expr val-exr

 

 

|

 

#:omit-define-syntaxes

 

 

|

 

#:omit-define-values

 

 

 

 

 

field-option

 

=

 

#:immutable

 

 

|

 

#:auto

Creates a new structure type, and binds transformers and variables related to the new structure type. A define-struct form with n fields defines up to 4+2n names:

If super-id is provided, it must have a transformer binding of the same sort bound to id (see Structure Type Transformer Binding), and it specifies a supertype for the new structure type. Alternately, the #:super option can be used to specify an expression that must produce a structure type descriptor. See Structures for more information on structure subtypes and supertypes. If both super-id and #:super are provided, a syntax error is reported.

If the #:immutable option is specified for an individual field, then the field cannot be mutated in instances of the structure type, and no mutator procedure is bound. Supplying #:immutable as a struct-option is the same as supplying it for all fields. If #:immutable is specified as both a field-option and struct-option, a syntax error is reported.

The #:inspector, #:auto-value, and #:guard options specify an inspector, value for automatic fields, and guard procedure, respectively. See make-struct-type (in Creating Structure Types) for more information on these properties of a structure type. The #:property option, which is the only one that can be specified multiple times, attaches a property value to the structure type; see Structure Type Properties for more information on properties.

If the #:omit-define-syntaxes option is supplied, then id is not bound as a transformer. If the #:omit-define-values option is supplied, then none of the usual variables are bound. If both are supplied, then the define-struct form is equivalent to (begin).

If #:auto is supplied as a field-option, then the constructor procedure for the structure type does not accept an argument corresponding to the field. Instead, the structure type’s automatic value is used for the field, as specified by the #:auto-value option, or as defaults to #f when #:auto-value is not supplied.

If a field includes the #:auto option, then all fields after it must also include #:auto, otherwise a syntax error is reported. If any field-option or struct-option keyword is repeated, other than #:property, a syntax error is reported.

Examples:

  (define-struct posn (x y [z #:auto])

                 #:auto-value 0

                 #:inspector #f)

  > (make-posn 1 2)

  #4(struct:posn 1 2 0)

  > (posn? (make-posn 1 2))

  #t

  > (posn-y (make-posn 1 2))

  2

  (define-struct (color-posn posn) (hue))

  (define cp (make-color-posn 1 2 "blue"))

  > (color-posn-hue cp)

  "blue"

  > cp

  #5(struct:color-posn 1 2 3 ...)

  > (set-posn-z! cp 3)

(struct-field-index field-id)

This form can only appear as an expression within a define-struct form; normally, it is used with #:property, especially for a property like prop:procedure. The result of

Examples:

  (define-struct mood-procedure ([base #:immutable] rating)

                 #:property prop:procedure (struct-field-index base))

  (define happy+ (make-mood-procedure add1 10))

  > (happy+ 2)

  3

  > (mood-procedure-rating happy+)

  10

5.2 Creating Structure Types

(make-struct-type

 

name

 

 

 

super-type

 

 

 

init-field-cnt

 

 

 

auto-field-cnt

 

 

 [

auto-v

 

 

 

props

 

 

 

inspector

 

 

 

proc-spec

 

 

 

immutables

 

 

 

guard])

 

 

 

(values struct-type?

        struct-constructor-procedure?

        struct-predicate-procedure?

        struct-accessor-procedure?

        struct-mutator-procedure?)

  name : symbol?

  super-type : (or/c struct-type? false/c)

  init-field-cnt : nonnegative-exact-integer?

  auto-field-cnt : nonnegative-exact-integer?

  auto-v : any/c = #f

  

props

 

:

 

(listof (cons/c struct-type-property?

                any/c))

 

=

 

null

  inspector : (or/c inspector? false/c) = (current-inspector)

  

proc-spec

 

:

 

(or/c procedure?

      nonnegative-exact-integer?

      false/c)

 

=

 

#f

  immutables : (listof nonnegative-exact-integer?) = null

  guard : (or/c procedure? false/c) = #f

Creates a new structure type. The name argument is used as the type name. If super-type is not #f, the new type is a subtype of the corresponding structure type.

The new structure type has init-field-cnt+auto-field-cnt fields (in addition to any fields from super-type), but only init-field-cnt constructor arguments (in addition to any constructor arguments from super-type). The remaining fields are initialized with auto-v.

The props 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. See Structure Type Properties for more information about properties.

The inspector argument controls access to reflective information about the structure type and its instances; see Structure Inspectors for more information.

If proc-spec is an integer or procedure, instances of the structure type act as procedures. See prop:procedure for further information. Providing a non-#f value for proc-spec is the same as pairing the value with prop:procedure in props, plus including proc-spec in immutables when proc-spec is an integer.

The immutables argument provides a list of field positions. Each element in the list must be unique, otherwise exn:fail:contract exception is raised. Each element must also fall in the range 0 (inclusive) to init-field-cnt (exclusive), otherwise exn:fail:contract exception is raised.

The guard argument is either a procedure of n arguments or #f, where n is the number of arguments for the new structure type’s constructor (i.e., init-field-cnt plus constructor arguments implied by super-type, if any). If guard is a procedure, then the procedure is called whenever an instance of the type is constructed, or whenever an instance of a subtype is created. The arguments to guard are the values provided for the structure’s first n fields, followed by the name of the instantiated structure type (which is name, unless a subtype is instantiated). The guard result must be n values, which become the actual values for the structure’s fields. The guard can raise an exception to prevent creation of a structure with the given field values. If a structure subtype has its own guard, the subtype guard is applied first, and the first n values produced by the subtype’s guard procedure become the first n arguments to guard.

The result of make-struct-type is five values:

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

  > (define-values (struct:b make-b b? b-ref b-set!)

      (make-struct-type 'b struct:a 1 2 'b-uninitialized))

  > (define a-b (make-b 'x 'y 'z))

  > (a-ref a-b 1)

  y

  > (a-ref a-b 2)

  uninitialized

  > (b-ref a-b 0)

  z

  > (b-ref a-b 1)

  b-uninitialized

  > (b-ref a-b 2)

  b-uninitialized

  > (define-values (struct:c make-c c? c-ref c-set!)

      (make-struct-type

       'c struct:b 0 0 #f null (make-inspector) #f null

       ; guard checks for a number, and makes it inexact

       (lambda (a1 a2 b1 name)

         (unless (number? a2)

           (error (string->symbol (format "make-~a" name))

                  "second field must be a number"))

         (values a1 (exact->inexact a2) b1))))

  > (make-c 'x 'y 'z)

  make-c: second field must be a number

  > (define a-c (make-c 'x 2 'z))

  > (a-ref a-c 1)

  2.0

(make-struct-field-accessor

 

accessor-proc

 

 

 

 

 

 

field-pos

 

 

 

 

 

 

field-name)

 

 

procedure?

  accessor-proc : struct-accessot-procedure?

  field-pos : exact-nonnegative-integer?

  field-name : symbol?

Returns a field accessor that is equivalent to (lambda (s) (accessor-proc s field-pos)). 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 and the name of accessor-proc’s structure type.

For examples, see make-struct-type.

(make-struct-field-mutator

 

mutator-proc

 

 

 

 

 

 

field-pos

 

 

 

 

 

 

field-name)

 

 

procedure?

  mutator-proc : struct-mutator-procedure?

  field-pos : exact-nonnegative-integer?

  field-name : symbol?

Returns a field mutator that is equivalent to (lambda (s v) (mutator-proc s field-pos 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 and the name of mutator-proc’s structure type.

For examples, see make-struct-type.

5.3 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 Creating Structure Types) or through the #:property option of define-struct. Subtypes inherit the property values of their parent types, and subtypes can override an inherited property value with a new value.

(make-struct-type-property name [guard])

 

 

(values struct-type-property?

        procedure?

        procedure?)

  name : symbol?

  guard : (or/c procedure? false/c) = #f

Creates a new structure type property and returns three values:

If the optional guard is supplied as a procedure, it is called by make-struct-type before attaching the property to a new structure type. The guard-proc must accept two 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 immediate current-inspector control check (but not the check for exposing an ancestor structure type, if any; see Structure Inspectors).

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

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

(struct-type-property? v)  boolean?

  v : any/c

Returns #t if v is a structure type property descriptor value, #f otherwise.

5.4 Structure Utilities

(struct->vector v [opaque-v])  vector?

  v : any/c

  opaque-v : any/c = '...

Creates a vector representing v. The first slot of the result vector contains a symbol whose printed name has the form struct:id. 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.)

(struct? v)  any

  v : any/c

Returns #t if struct->vector exposes any fields of v with the current inspector, #f otherwise.

(struct-type? v)  boolean?

  v : any/c

Returns #t if v is a structure type descriptor value, #f otherwise.

(struct-constructor-procedure? v)  boolean?

  v : any/c

Returns #t if v is a constructor procedure generated by define-struct or make-struct-type, #f otherwise.

(struct-predicate-procedure? v)  boolean?

  v : any/c

Returns #t if v is a predicate procedure generated by define-struct or make-struct-type, #f otherwise.

(struct-accessor-procedure? v)  boolean?

  v : any/c

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)  boolean?

  v : any/c

Returns #t if v is a mutator procedure generated by define-struct, make-struct-type, or make-struct-field-mutator, #f otherwise.

5.5 Structure Type Transformer Binding

The define-struct form binds the name of a structure type as a transformer binding that records the other identifiers bound to the structure type, the constructor procedure, the predicate procedure, and the field accessor and mutator procedures. This information can be used during the expansion of other expressions via syntax-local-value.

For example, the define-struct variant for subtypes uses the base type name t to find the variable struct@scheme [:t] containing the base type’s descriptor; it also folds the field accessor and mutator information for the base type into the information for the subtype. As another example, the match form uses a type name to find the predicates and field accessors for the structure type. The struct form in an imported signature for unit causes the unit transformer to generate information about imported structure types, so that match and subtyping define-struct forms work within the unit.

The expansion-time information for a structure type is represented as a list of six elements:

The implementor of a syntactic form can expect users of the form to know what kind of information is available about a structure type. For example, the match implementation works with structure information containing an incomplete set of accessor bindings, because the user is assumed to know what information is available in the context of the match expression. In particular, the match expression can appear in a unit form with an imported structure type, in which case the user is expected to know the set of fields that are listed in the signature for the structure type.

 

contents

 index

← prev  up  next →