rebellion icon indicating copy to clipboard operation
rebellion copied to clipboard

Data type guards

Open jackfirth opened this issue 5 years ago • 3 comments

Analogous to struct-guard/c, there should be xxx-guard/c contract combinators for use with each kind of type in rebellion/type. They should provide APIs similar to the constructors of the kind of types they're meant for. Subtasks:

  • [ ] Wrapper type guards (#202)
  • [ ] Tuple type guards (#203)
  • [ ] Record type guards (#204)

jackfirth avatar Mar 03 '19 03:03 jackfirth

Notes on API designs currently being explored:

  • The guard functions should accept values for each field and an extra value with information about the type, so the guard function can raise errors that use the type's name and field names.

  • The type information should usually be given first, then the guard should return a function that accepts the field values. This allows a guard to make assertions about the shape of the type. Tuple guards (#203) and record guards (#204) both need this feature, but wrapper guards (#202) don't.

  • Currently, guards are just plain functions. But maybe they should be functions wrapped by a struct, to make it easier to check first-order properties about them and to make the guard APIs easier to work with.

  • Guards are most important for types that are usually used as plain bags of data (wrappers, tuples, records), rather than types that seal away some opaque fields (reference types). The former are much higher priority than the latter.

  • Singleton type guards seem pointless.

  • Guards ought to be able to normalize and convert field values. This makes them slightly more powerful than plain chaperone contracts, since they don't have to return equal? values. But they're not applied on field accesses, only on instance construction. Additionally, this normalization should be idempotent.

  • Guards ought to be able to check constraints across multiple fields. Example: a bounds tuple type with a min field and a max field should enforce that min <= max. This might require a dependent contract combinator, or maybe there's room for some sort of "multicontract" API.

jackfirth avatar Sep 10 '19 20:09 jackfirth

Combined with #177, this would allow deleting a ton of the boilerplate associated with defining and providing a non-generic data type. Candidates within rebellion include:

  • Media and media types rebellion/media
  • Octet streams rebellion/media/application/octet-stream
  • Points rebellion/point
  • Text media rebellion/media/text/plain
  • Web graphs rebellion/web-graph
  • Web links rebellion/web-link

jackfirth avatar Sep 10 '19 21:09 jackfirth

The API for this seems mostly designed for now, see the three subtasks.

jackfirth avatar Sep 10 '19 22:09 jackfirth