On this page:
struct
foreign.struct
union
foreign.union
list_  t
array_  t
#%parens
0.45+9.2.0.5

2.3 Compound Foreign Types🔗ℹ

foreign type

struct maybe_tag (

  field_id :: field_type,

  ...

)

 

definition

foreign.struct id (

  field_id :: field_type,

  ...

)

 

maybe_tag

 = 

id

 | 

ϵ

The struct type form describes a type that is represented by a struct declaration on the C side and a pointer object in the Rhombus side. If maybe_tag is an identifier, the name of the identifier is suffixed with * used as a tag for pointers that represent instances of the struct type, otherwise a generic ptr_t pointer is used.

Each field_id must be distinct, and the corresponding field_type describes the field’s representation on the C side and the representation used on the Rhombus side if the field’s value is extracted from a representation of the struct type.

The foreign.struct form defines id as an alias for the corresponding struct type using id like maybe_tag for a pointer tag. The id is also defined for additional roles:

  • The id is defined as an annotation that recognizes pointers tagged with id.

  • The id is defined as a veneer, and id as a type implies the static information of id as a veneer. Each field_id is bound as a field of the veneer that can be used to access or update the corresponding field in an instance of the struct.

    • When a field is accessed, the result is a representation of the corresponding C field value based on the conversion implied by the associated field_type.

    • When the field is set using := to a Rhombus value, a value converted to C based on the associated field_type, and that C value is installed into the struct instance.

  • The id is defined for use with new allocate to an instance of the struct with field values provided as arguments (in addition to the possibility of using id by itself as a type to create an uninitialized instance).

Note that the Racket-side representation is the same for id and id*, even though the C-side representation differs.

foreign.struct point_t(x :: double_t,

                       y :: double_t)

> sizeof(point_t)

16

> sizeof(point_t*)

8

> def p1 = new point_t(1.0, 2.0)

> p1

#<point_t*/gcable>

> p1 is_a point_t

#true

> p1 is_a foreign.type point_t*

#true

> p1.x

1.0

> p1.y

2.0

> p1.x := 5.0

> p1.x

5.0

> point_t.x(p1)

5.0

> point_t.x(malloc(16))

point_t.x: not an instance for method call

  value: #<ptr_t/gcable>

With this example’s definition of point_t, a field in another struct type would take up 16 bytes, while a point_t* field would take up 8 bytes. Accessing the field in either case would produce a Racket representation that is a pointer tagged as point_t*. In the case of a point_t field, the returned pointer would refer to memory within the accessed struct instance.

Along similar lines, a pointer tagged with point_t* is suitable as an argument to a C function that has either a point_t or point_t* argument. In the case of a point_t argument, the C function receives a copy of the content of the pointer. In the case of a point_t* argument, the C function receives the same address as encapsulated by the pointer.

foreign type

union maybe_tag (

  field_id :: field_type,

  ...

)

 

definition

foreign.union id (

  field_id :: field_type,

  ...

)

Similar to struct and foreign.struct, but for a type that uses union on the C side.

The use of a defined id with new plus arguments is different than for a type defined with foreign.struct, since a foreign.union instance is a variant for only one of the fields, not a composite value with all of the fields. To specify the relevant variant, there must be only one argument, and it must be in a block that is prefixed with the relevant $field_id.

foreign.union grade_t (score :: double_t,

                       pass_fail :: bool_t)

> sizeof(grade_t)

8

> def g1 = new grade_t(score: 93.0)

> g1.score

93.0

> def g2 = new grade_t(pass_fail: #true)

> g2.pass_fail

#true

> def g3  = new grade_t(score: 0.0)

> g3.pass_fail

#false

foreign type

list_t maybe_mode (elem_type) maybe_length

 

foreign type

array_t maybe_mode (elem_type) maybe_length

 

maybe_length

 = 

~length len_expr

 | 

ϵ

Describes a type with a C representation that is the same as elem_type*, but with a Rhombus representation that is a list or array. The elements of the list or array are Rhombus representations for elem_type.

When converting from Rhombus to C, memory is allocated using new, maybe_mode, and the length of the list or array. A ~length specification is used only when converting from C back to Rhombus, since a elem_type* does not encode a length. If ~length is not provided, it defaults to 0which is useless, but safe.

foreign type

#%parens (type)

 

foreign type

#%parens (arg, ...)

 

foreign type

#%parens (arg, ..., ~varargs, arg, ...)

The #%parens prefix operator is an implicit form and not usually written explicitly: (group, ...) is equivalent to #%parens (group, ...).

A type form (type) is equivalent to type.

A (arg, ...) or (arg, ..., ~varargs, arg, ...) form is allowed as a “type” only on the left-hand side of the -> operator.