On this page:
_ cpointer
_ cpointer/ null
define-cpointer-type
cpointer-has-tag?
cpointer-push-tag!

5.3 Tagged C Pointer Types

The unsafe cpointer-has-tag? and cpointer-push-tag! operations manage tags to distinguish pointer types.

procedure

(_cpointer tag    
  [ptr-type    
  scheme-to-c    
  c-to-scheme])  ctype
  tag : any/c
  ptr-type : ctype? = _pointer
  scheme-to-c : (any/c . -> . any/c) = values
  c-to-scheme : (any/c . -> . any/c) = values
(_cpointer/null tag    
  [ptr-type    
  scheme-to-c    
  c-to-scheme])  ctype
  tag : any/c
  ptr-type : ctype? = _pointer
  scheme-to-c : (any/c . -> . any/c) = values
  c-to-scheme : (any/c . -> . any/c) = values
Construct a kind of a pointer that gets a specific tag when converted to Racket, and accept only such tagged pointers when going to C. An optional ptr-type can be given to be used as the base pointer type, instead of _pointer.

Although any value can be used as a tag, by convention the symbol form of a type name—without a leading underscore—is used as the tag. For example, a pointer type _animal would normally use 'animal as the key.

Pointer tags are checked with cpointer-has-tag? and changed with cpointer-push-tag!, which means that other tags are preserved on an existing pointer value. Specifically, if a base ptr-type is given and is itself a _cpointer, then the new type will handle pointers that have the new tag in addition to ptr-type’s tag(s). When the tag is a pair, its first value is used for printing, so the most recently pushed tag which corresponds to the inheriting type is displayed.

The _cpointer/null function is similar to _cpointer, except that it tolerates NULL pointers both going to C and back. Note that NULL pointers are represented as #f in Racket, so they are not tagged.

syntax

(define-cpointer-type _id)

(define-cpointer-type _id ptr-type-expr)
(define-cpointer-type _id ptr-type-expr
                      scheme-to-c-expr c-to-scheme-expr)
A macro version of _cpointer and _cpointer/null, using the defined name for a tag symbol, and defining a predicate too. The _id must start with _.

The optional expressions produce optional arguments to _cpointer.

In addition to defining _id to a type generated by _cpointer, _id/null is bound to a type produced by _cpointer/null type. Finally, id? is defined as a predicate, and id-tag is defined as an accessor to obtain a tag. The tag is the symbol form of id.

procedure

(cpointer-has-tag? cptr tag)  boolean?

  cptr : any/c
  tag : any/c
(cpointer-push-tag! cptr tag)  void
  cptr : any/c
  tag : any/c
These two functions treat pointer tags as lists of tags. As described in Pointer Functions, a pointer tag does not have any role, except for Racket code that uses it to distinguish pointers; these functions treat the tag value as a list of tags, which makes it possible to construct pointer types that can be treated as other pointer types, mainly for implementing inheritance via upcasts (when a struct contains a super struct as its first element).

The cpointer-has-tag? function checks whether if the given cptr has the tag. A pointer has a tag tag when its tag is either eq? to tag or a list that contains (in the sense of memq) tag.

The cpointer-push-tag! function pushes the given tag value on cptr’s tags. The main properties of this operation are: (a) pushing any tag will make later calls to cpointer-has-tag? succeed with this tag, and (b) the pushed tag will be used when printing the pointer (until a new value is pushed). Technically, pushing a tag will simply set it if there is no tag set, otherwise push it on an existing list or an existing value (treated as a single-element list).