Documentation:Special form define-record-type

From Gambit wiki

(Redirected from Define-type)
Jump to: navigation, search


User contributed comments, clarifications and examples

Mark Feeley explains Gambit-C Records on r6rs-editors

There is also an extensive documentation made for SchemeSpheres that you might find useful as well.

Content from define-type on main wiki page

define-type / define-structure usage

Here is a traduction of some of Marc's slides from an introduction to scheme course. I believe they might be usefull since define-type / define-record are very lightly documented in the official doc.


(define-type type-name <attribute or field>...)

Attribute is a keyword. An attribute may have arguments?

Field is a symbol or a list. If a list, the first element is the field name, optionally followed by getter and setter, then field attributes

The simplest form of syntax specifies only the type name and the name of each fields

  • ex:
C: typedef struct { int x; int y; } point2d;
Gambit : (define-type point2d x y)
  • Such type definition are equivalent to multiple definitions:
(define (make-point2d x y)...)   ;constructor
(define (point2d? obj)... )      ;predicate
(define (point2d-x p)...)        ;access to x field
(define (point2d-x-set! p x)...) ;mutation of x field
(define (point2d-y p)...)        ;access to y field
(define (point2d-y-set! p y)...) ;mutation of y field
  • ex:
> (define-type point2d x y)
> (define p (make-point2d 11 22))
> p
#<point2d #2 x: 11 y: 22>
> (point2d? p)
> (point2d-x p)
> (point2d-x-set! p 33)
> p
#<point2d #2 x: 33 y: 22>

define-type attributes

  • These structures also supports inheritance
  • The parameter extender: name specifies the name of the definition form to use to define a subtype:
> (define-type point2d
    extender: define-type-of-point2d
> (define-type-of-point2d point3d z)
> (define p3 (make-point3d 11 22 33))
> p3
#<point3d #2 x: 11 y: 22 z: 33>
> (point2d? p3)
> (point3d? p3)
> (point2d-x p3)
> (point3d-z p3)
  • id: uuid

Specifies an identifier that is used to name this precise type uniquely, which is used during (de)serialization via object->u8vector and u8vector->object.

  • constructor: name

Specifies the name of the generated constructor macro.

  • predicate: name

Specifies the name of the generated function/macro for testing if a value has this type.

  • prefix: pfx

All generated functions/macros will have pfx before their regular name. For example:

> (define-type foo prefix: xyz a b)
> (xyzmake-foo 1 2)
#<foo #2 a: 1 b: 2>
> (xyzfoo-a (xyzmake-foo 1 2))
  • macros:

Do not generate procedures for any purpose; the predicate and all field getters/setters will be macros.

> (define-type foo a b)
> foo-a
#<procedure #2 foo-a>
> (define-type bar macros: a b)
> bar-a
*** ERROR IN (console)@4.1 -- Macro name can't be used as a variable: bar-a
  • constant-constructor:

Specifies a constructor that creates constants (available at compile-time). Can be used only with non-generative type definitions.

  • implementer:

Adds a definition of the parameterless macro "implementer-name" that expands to all non-macro definitions produced by the define-type. This is useful to distinguish the two binding times (compile-time and run time). It can be used to avoid duplicate definitions when a file containing a define-type is included in multiple files (I think this problem should be solved through the module system, but this is how the problem can be solved without a module system). For example, let's say the file point-def.scm contains the definition of the point type, and files a.scm and b.scm need to manipulate points.

  • type-exhibitor:

If specified will create a function with no arguments that returns the type descriptor of this type without the need of creating an instance.

  • opaque:

This flag causes a change in the behavior of equal? and equal?-hash. When the opaque: flag is not used, two structures are equal? if they have the same type and each field is equal? in both structures. When the opaque: flag is used, two structures are equal? only if they are eq? (i.e. the same instance).

Field attributes

  • read-write:

Default option. A setter procedure/macro is generated.

  • read-only:

No setter is generated, effectively rendering the field read-only after it is set by the constructor.

  • equality-test:

Default option. Testing type instances using equal? will check the values of this field as part of that test.

  • equality-skip:

Testing type instances using equal? will ignore the values of this field.

> (define-type alpha x y)
> (equal? (make-alpha 0 1) (make-alpha 0 2))
> (define-type beta x (y equality-skip:))
> (equal? (make-beta 0 1) (make-beta 0 2))
  • printable:

Default option. The field will be printed when the type instance itself is.

  • unprintable:

The field will not be printed when the type instance is printed.

> (define-type foo a (b unprintable:))
> (make-foo 1 2)
#<foo #3 a: 1>
  • init: cst

Set the initial value to literal value cst. Note that this does not make the field optional in the constructor; the field can not be provided when using the constructor.

> (define-type alpha a (b init: 1))
> (make-alpha 0 99)
*** ERROR IN (console)@2.1 -- Wrong number of arguments passed to procedure
(make-alpha 0 99)
> (make-alpha 0)
#<alpha #2 a: 0 b: 1>


> (define-type noeud
    (a unprintable:)
    (b read-only: init: 9)
    (c equality-skip:))
> (define x (make-noeud 1 2))
> (noeud-a-set! x x)
> x
#<noeud #2 b: 9 c: 2>
> (equal? x (make-noeud x 3))
> (noeud-b-set! x 999)
*** ERROR -- Unbound variable: noeud-b-set!

Other Information

All field attributes except init: can be specified at define-type level and will affect all fields. A field can specify its own field attributes to override default attributes.

  • ex:
> (define-type foo unprintable: a (b printable:))
> (make-foo 1 2)
#<foo #3 b: 2>
  • Field may have non-conventional getter and setter names, specified after field name in that order
  • ex:
> (define-type foo (a get-a) (b get-b set-b))
> (define x (make-foo 1 2))
> (get-a x)
> (set-a x 2)
*** ERROR IN (console)@14.2 -- Unbound variable: set-a
> (get-b x)
> (set-b x 3)
> (get-b x)
Personal tools