5.2 Creating Structure Types
procedure
(make-struct-type name super-type init-field-cnt auto-field-cnt [ auto-v props inspector proc-spec immutables guard constructor-name]) name : symbol? super-type : (or/c (and/c struct-type? (not/c struct-metatype?)) #f) init-field-cnt : exact-nonnegative-integer? auto-field-cnt : exact-nonnegative-integer? auto-v : any/c = #f
props :
(listof (cons/c struct-type-property? any/c)) = null inspector : (or/c inspector? #f 'current 'prefab) = 'current
proc-spec :
(or/c procedure? exact-nonnegative-integer? #f) = #f immutables : (listof exact-nonnegative-integer?) = null guard : (or/c procedure? #f) = #f constructor-name : (or/c symbol? #f) = #f
The resulting 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 total field count (including super-type fields) must be no more than 32768.
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. A property can be specified multiple times in props (including properties that are automatically added by properties that are directly included in props) only if the associated values are eq?, otherwise the exn:fail:contract exception is raised. See Structure Type Properties for more information about properties. When inspector is 'prefab, then props must be null.
The inspector argument normally controls access to reflective information about the structure type and its instances; see Structure Inspectors for more information. If inspector is 'prefab, then the resulting prefab structure type and its instances are always transparent. If inspector is #f, then the structure type’s instances are transparent. If inspector is 'current (the default), then the (current-inspector) is used.
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 at the end of 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+1 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. When inspector is 'prefab, then guard must be #f.
If constructor-name is not #f, it is used as the name of the generated constructor procedure as returned by object-name or in the printed form of the constructor value.
The result of make-struct-type is five values:
a constructor procedure,
a predicate procedure,
an accessor procedure, which consumes a structure and a field index between 0 (inclusive) and init-field-cnt+auto-field-cnt (exclusive), and
a mutator procedure, which consumes a structure, a field index, and a field value.
(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
(define p1 #s(p a b c)) (define-values (struct:p make-p p? p-ref p-set!) (make-struct-type 'p #f 3 0 #f null 'prefab #f '(0 1 2)))
> (p? p1) #t
> (p-ref p1 0) 'a
> (make-p 'x 'y 'z) '#s(p x y z)
Changed in version 9.0.0.6 of package base: Added 'current as an allowed value for inspector.
procedure
(make-struct-field-accessor accessor-proc field-pos [ field/proc-name arg-contract-str realm]) → struct-accessor-procedure?
accessor-proc :
(and/c struct-accessor-procedure? (procedure-arity-includes/c 2)) field-pos : exact-nonnegative-integer?
field/proc-name : (or/c symbol? #f) = (symbol->string (format "field~a" field-pos)) arg-contract-str : (or/c string? symbol? #f) = #f realm : symbol? = 'racket
The field/proc-name argument determines the name of the resulting procedure for error reporting and debugging purposes. If field/proc-name is a symbol and arg-contract-str is not #f, then field/proc-name is used as the procedure name. If field/proc-name is a symbol and arg-contract-str is #f, then field/proc-name is combined with the name of accessor-proc’s structure type to form the procedure name. If field/proc-name is #f, then 'accessor is used as the procedure name.
The arg-contract-str argument determines how the accessor procedure reports an error when it is applied to a value that is not an instance of the accessor-proc’s structure type. If it is a string or symbol, the text of the string or symbol is used as a contract for error reporting. Otherwise, contract text is synthesized from the name of accessor-proc’s structure type.
The realm argument is also used for error reporting. It specifies a realm that an error-message adjuster may use to determine how to adjust an error message. The realm argument also determines the result of procedure-realm for the accessor procedure.
For examples, see make-struct-type.
Changed in version 8.4.0.2 of package base: Added the arg-contract-str and realm arguments.
procedure
(make-struct-field-mutator mutator-proc field-pos [ field/proc-name arg-contract-str realm]) → struct-mutator-accessor-procedure?
mutator-proc :
(and/c struct-mutator-procedure? (procedure-arity-includes/c 3)) field-pos : exact-nonnegative-integer?
field/proc-name : (or/c symbol? #f) = (symbol->string (format "field~a" field-pos)) arg-contract-str : (or/c string? symbol? #f) = #f realm : symbol? = 'racket
The field-name, arg-contract-str, and realm arguments are used for error and debugging purposes analogous to the same arguments to make-struct-field-accessor.
For examples, see make-struct-type.
Changed in version 8.4.0.2 of package base: Added the arg-contract-str and realm arguments.
value
A sealed structure type cannot be used as the supertype of another structure type. Declaring a structure type as sealed is typically just a performance hint, since checking for an instance of a sealed structure type can be slightly faster than checking for an instance of a structure type that might have subtypes.
Added in version 8.0.0.7 of package base.
procedure
(make-struct-metatype name super-metatype init-field-cnt [ authenticity])
→
struct-type? (procedure-arity-includes/c (+ 11 init-field-cnt)) struct-predicate-procedure?
(and/c struct-metaaccessor-procedure? struct-accessor-procedure? (procedure-arity-includes/c 2)) name : symbol? super-metatype : (or/c struct-metatype? #f) init-field-cnt : exact-nonnegative-integer?
authenticity : (or/c #f 'metaauthentic 'authentic) = 'metaauthentic
The result is four values:
metastruct:name: A structure metatype that is instantiated by each structure type (not its instances) produced by calling the make-name-type result. If super-metatype is provided, structure types produced by make-name-type are also instances of super-metatype.
The metastruct:name result also counts as a structure type, but it is instantiated only as other structure types. As a structure type, metastruct:name is controlled by an inspector that has no parent (so the structure type cannot be inspected via struct-type-info, for example).
If authenticity is 'metaauthentic or 'authentic, then metastruct:name is created with prop:authentic. If super-metatype is provided, it must have the same authenticity.
make-name-type: A procedure like make-struct-type, but all arguments of make-struct-type are required for make-name-type, and make-name-type requires init-field-cnt additional arguments. If super-metatype, it contributes additional required arguments before the init-field-cnt additional arguments.
If authenticity is 'authentic, then every structure type created by make-name-type has prop:authentic.
name?: A predicate to recognize structure types produced by make-name-type or a submetatype’s maker.
name-ref: An accessor procedure for use on a result of make-name-type to extract one of the additional init-field-cnt arguments that were provided to make-name-type. This accessor is analogous to the position-based accessor returned by make-struct-type, and it can be converted to a position-specific accessor using make-struct-field-accessor. The accessor’s argument can be any metastruct:name, including structure types produced via makers of a submetatypes.
The name-ref procedure can be provided to chaperone-struct to interpose on extraction of an instance’s structure type, as long as authenticity is not 'authentic and the instance’s strcuture type is itself of an instance of metastruct:name.
See also make-struct-field-metaaccessor and make-struct-type-accessor.
A structure type produced by make-name-type can be used as supertype for make-struct-type or vice-versa. A structure metatype produced by make-struct-metatype cannot be used as a supertype for make-struct-type, and super-metatype cannot be a structure type produced by make-struct-type or by any make-name-type produced by make-struct-type.
Fields added in a structure metatype are similar to property values that can associated with a structure type by supplying a structure type property to make-struct-type. Structure metatype fields may be accessed more efficiently than property values, however, due to the single-inheretance nature of metatypes.
> (define-values (struct:klass make-klass-struct-type klass-type? klass-type-ref) (make-struct-metatype 'klass #f 1)) > (define klass-vtable (make-struct-field-accessor klass-type-ref 0)) > (define instance-vtable (make-struct-field-metaaccessor klass-type-ref 0))
> (define-values (struct:posn make-posn posn? posn-ref posn-set!) (make-klass-struct-type 'p #f 2 0 #f null 'current #f '(0 1) #f #f (vector (lambda (p) (list 'x '= (posn-ref p 0))) (lambda (p) (list 'y '= (posn-ref p 1)))))) > (define p (make-posn 1 2)) > ((vector-ref (instance-vtable p 'oops) 0) p) '(x = 1)
> ((vector-ref (instance-vtable p 'oops) 1) p) '(y = 2)
> (eq? ((make-struct-type-metaaccessor klass-type-ref) p 'oops) struct:posn) #t
Added in version 9.3.0.6 of package base.
procedure
(struct-metatype? v) → boolean?
v : any/c
Added in version 9.3.0.6 of package base.
procedure
(make-struct-field-metaaccessor accessor-proc field-pos) → (procedure-arity-includes/c 2) accessor-proc : struct-metaaccessor-procedure? field-pos : exact-nonnegative-integer?
The resulting procedure accepts two argument: the structure whose structure type is accessed, and a default value to return if the first argument is not an instance of a structure type recognized by accessor-proc. In other words, the resulting procedure never throws an exception when given two arguments.
See make-struct-metatype for an example.
Added in version 9.3.0.6 of package base.
procedure
(make-struct-type-metaaccessor accessor-proc)
→ (procedure-arity-includes/c 2) accessor-proc : struct-metaaccessor-procedure?
See make-struct-metatype for an example.
Added in version 9.3.0.6 of package base.