2.7 Object Types
(require rebellion/type/object) | package: rebellion |
An object type is a kind of data type for opaque named values. Object types are similar to record types in that they both have an unordered set of fields and a keyword-based constructor. However, object types are intended for encapsulating behavior, not data. In support of this, object types have an automatic #:name field used to implement prop:object-name. Instead of printing their fields, instances of object types print like other named opaque values such as functions and ports and print only their names.
As a rule of thumb, if you want to simply bundle together data then use record types. But if you want to group together functions or other complex objects, and you don’t want to give users access to them, use object types. Examples of object types in Rebellion include converters, comparators, reducers, and transducers.
syntax
(define-object-type id (field-id ...) option ...)
option = #:omit-root-binding | #:descriptor-name descriptor-id | #:predicate-name predicate-id | #:constructor-name constructor-id | #:accessor-name accessor-id | #:property-maker prop-maker-expr | #:inspector inspector-expr
prop-maker-expr :
(-> uninitialized-object-descriptor? (listof (cons/c struct-type-property? any/c)))
inspector-expr : inspector?
constructor-id, which defaults to make-id —
an object constructor that accepts one mandatory keyword argument for each field-id and one optional #:name argument, then constructs an instance with the given name. The name argument must be either an interned symbol or false (the default). If the name argument is false, then the constructed instance is anonymous and its printed representation will not include a name. predicate-id, which defaults to id? —
a predicate function that returns #t when given instances of the created type and returns #f otherwise. id-field-id for each field-id (including the automatically-added name field) —
a field accessor function that returns the value for field-id when given an instance of the created type. accessor-id, which defaults accessor:id —
an object accessor that accepts an instance of the created type and an integer indicating which field to access, then returns the value of that field. descriptor-id, which defaults to descriptor:id —
the type descriptor for the created type.
Additionally, unless #:omit-root-binding is specified, the original id is bound to an object type binding for the created type.
The prop-maker-expr is used to add structure type properties to the created type, and inspector-expr is used to determine the inspector that will control the created type. See make-object-implementation for more information about these parameters.
(define-object-type folder (accumulator initial-state)) (define (fold sequence folder) (define initial-state (folder-initial-state folder)) (define accumulator (folder-accumulator folder)) (for/fold ([state initial-state]) ([v sequence]) (accumulator state v))) (define sum (make-folder #:accumulator + #:initial-state 0 #:name 'sum))
> sum #<folder:sum>
> (fold (list 1 2 3 4) sum) 10
2.7.1 Object Type Information
procedure
(object-type? v) → boolean?
v : any/c
procedure
(object-type name fields [ #:name-field name-field #:constructor-name constructor-name #:predicate-name predicate-name #:accessor-name accessor-name]) → object-type? name : interned-symbol? fields : keyset? name-field : keyword? = '#:name constructor-name : (or/c interned-symbol? #f) = #f predicate-name : (or/c interned-symbol? #f) = #f accessor-name : (or/c interned-symbol? #f) = #f
The optional predicate-name, constructor-name, and accessor-name arguments control the result of object-name on the functions implementing the type. If not provided, predicate-name defaults to name?, constructor-name defaults to make-name, and accessor-name defaults to accessor:name.
This function only constructs the information representing an object type; to implement the type, use make-object-implementation.
procedure
(object-type-name type) → interned-symbol?
type : object-type?
procedure
(object-type-fields type) → keyset?
type : object-type?
procedure
(object-type-private-fields type) → keyset?
type : object-type?
procedure
(object-type-name-field type) → keyword?
type : object-type?
procedure
(object-type-name-field-position type) → natural?
type : object-type?
procedure
type : object-type?
procedure
type : object-type?
procedure
type : object-type?
procedure
(object-type-size type) → natural?
type : object-type?
2.7.2 Object Type Descriptors
The type descriptor for an object type contains two functions that implement the type:
An object constructor that accepts one argument for each field of the object type and constructs an object instance.
An object accessor that accepts an instance of the object type and an integer field index, then returns the value of the corresponding field.
These functions can be used to dynamically construct and inspect instances of arbitrary object types at runtime, assuming the type’s descriptor is initialized. Note that the descriptor contains a single accessor function that can access any field in the object: the per-field accessors created by define-object-type are merely convenient wrappers around this accessor.
procedure
(object-descriptor? v) → boolean?
v : any/c
procedure
v : any/c
procedure
v : any/c
procedure
(make-object-implementation type [ #:inspector inspector #:property-maker prop-maker]) → initialized-object-descriptor? type : object-type? inspector : inspector? = (current-inspector)
prop-maker :
(-> uninitialized-object-descriptor? (listof (cons/c struct-type-property? any/c))) = default-object-properties
procedure
(object-descriptor-type descriptor) → object-type?
descriptor : object-descriptor?
procedure
(object-descriptor-predicate descriptor) → predicate/c
descriptor : object-descriptor?
procedure
(object-descriptor-constructor descriptor) → procedure?
descriptor : object-descriptor?
procedure
(object-descriptor-accessor descriptor)
→ (-> (object-descriptor-predicate descriptor) natural? any/c) descriptor : object-descriptor?
procedure
(make-object-field-accessor descriptor field) → (-> (object-descriptor-predicate descriptor) any/c) descriptor : object-descriptor? field : natural?
procedure
(default-object-properties descriptor)
→ (listof (cons/c struct-type-property? any/c)) descriptor : object-descriptor?
procedure
(default-object-equal+hash descriptor) → equal+hash/c
descriptor : object-descriptor?
procedure
(default-object-custom-write descriptor)
→ custom-write-function/c descriptor : object-descriptor?
procedure
(default-object-name-property descriptor) → natural?
descriptor : object-descriptor?
2.7.3 Object Type Bindings
(require rebellion/type/object/binding) | package: rebellion |
An object type binding is a type binding for an object type. Object type bindings contain compile-time information about the object type’s name and fields, as well as runtime bindings for its predicate, type descriptor, and other runtime components. To extract an object type binding bound by define-object-type, use the object-id syntax class.
procedure
(object-binding? v) → boolean?
v : any/c
syntax class
type —
an attribute bound to a compile-time object-type? value describing the type. binding —
an attribute bound to the compile-time object-binding? value extracted from the matched identifier. name —
a pattern variable bound to the object type’s name, as a quoted symbol. descriptor —
a pattern variable bound to the object type’s runtime type descriptor. predicate —
a pattern variable bound to the object type’s runtime type predicate. constructor —
a pattern variable bound to the object type’s runtime object constructor. accessor —
a pattern variable bound to the object type’s runtime object accessor. field ... —
a pattern variable bound to the object’s field identifiers. This includes both the object type’s private fields and its name field. field-name ... —
a pattern variable bound to the object’s field names, as quoted symbols. This includes both the object type’s private fields and its name field. field-keywords ... —
a pattern variable bound to the object’s field names, as keywords. This includes both the object type’s private fields and its name field. field-accessor ... —
a pattern variable bound to the object type’s per-field runtime field accessors. This includes accessors for both the private fields and the name field. private-field ... —
a pattern variable bound to the object’s private field identifiers. The name field is not a private field. private-field-name ... —
a pattern variable bound to the object’s private field names, as quoted symbols. The name field is not a private field. private-field-keyword ... —
a pattern variable bound to the object’s private field names, as keywords. The name field is not a private field. private-accessor ... —
a pattern variable bound to the object type’s per-field runtime private field accessors. This does not include an accessor for the name field. name-field —
a pattern variable bound to the object’s name field identifier. name-field-name —
a pattern variable bound to the object’s name field, as a quoted symbol. name-field-keyword —
a pattern variable bound to the object’s name field, as a keyword. name-accessor —
a pattern variable bound to the object type’s name field accessor.
(require (for-syntax rebellion/type/object/binding)) (define-simple-macro (object-accessors object:object-id) (list object.field-accessor ...)) (define-object-type folder (accumulator initial-state))
> (object-accessors folder)
'(#<procedure:folder-accumulator>
#<procedure:folder-initial-state>
#<procedure:folder-name>)
procedure
(object-binding-type binding) → object-type?
binding : object-binding?
procedure
(object-binding-descriptor binding) → identifier?
binding : object-binding?
procedure
(object-binding-predicate binding) → identifier?
binding : object-binding?
procedure
(object-binding-constructor binding) → identifier?
binding : object-binding?
procedure
(object-binding-accessor binding) → identifier?
binding : object-binding?
procedure
(object-binding-fields binding)
→ (vectorof identifier? #:immutable #t) binding : object-binding?
procedure
(object-binding-field-accessors binding)
→ (vectorof identifier? #:immutable #t) binding : object-binding?
procedure
(object-binding-private-fields binding)
→ (vectorof identifier? #:immutable #t) binding : object-binding?
procedure
(object-binding-private-accessors binding)
→ (vectorof identifier? #:immutable #t) binding : object-binding?
procedure
(object-binding-name-field binding) → identifier?
binding : object-binding?
procedure
(object-binding-name-accessor binding) → identifier?
binding : object-binding?
2.7.4 Object Type Chaperones and Impersonators
procedure
(object-impersonate instance descriptor [ #:properties properties #:chaperone? chaperone?]) → (object-descriptor-predicate descriptor) instance : (object-descriptor-predicate descriptor) descriptor : initialized-object-descriptor?
properties : (hash/c impersonator-property? any/c #:immutable #t) = empty-hash chaperone? : boolean? = #t