rebellion
rebellion copied to clipboard
Data type guards
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)
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 amin
field and amax
field should enforce thatmin <= max
. This might require a dependent contract combinator, or maybe there's room for some sort of "multicontract" API.
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
The API for this seems mostly designed for now, see the three subtasks.