Skip to content

Consider adding common contracts to the standard library #2402

@twitchyliquid64

Description

@twitchyliquid64

Spawned off a discussion in discord: https://discord.com/channels/1174731094726295632/1179430745727586407/1432836461505417448

TL;DR: We should provide commonly-used contracts in the standard library. These should be

  • Composable
  • well thought-out
  • somewhat minimal (i.e. not 'the whole kitchen sink')

The two things I find myself reaching for are this:

1. "If X, apply contract Y"

Nickel snippet - what im using now
    RuntimeDep | doc "Possible values for a runtime dependency entry." = fun Contract =>
        std.contract.custom (fun label value =>
            match {
                {ty = 'Builder, ..} => std.contract.check BuildSpec label value,
                {ty = 'Subset, ..} => std.contract.check Subset label value,
                _ => 'Error {
                    message = "Expected Input type",
                },
            }
            value
        ),

2. "field X or field Y but not both"

Nickel snippet which @jneem cooked up
let OneOrTheOther | String -> String -> Dyn = fun fld1 fld2 =>
  std.contract.from_validator (fun value =>
    if !std.is_record value then
      'Error { message = "expected a record" }
    else
      let
        has1 = std.record.has_field fld1 value,
        has2 = std.record.has_field fld2 value,
      in
      if has1 && has2 then
        'Error { message = "`%{fld1}` and `%{fld2}` cannot both be defined" }
      else if !has1 && !has2 then
        'Error { message = "either `%{fld1}` or `%{fld2}` must be defined" }
      else
        'Ok
  )
in
{
  foo = 1,
  bar = 1,
} | OneOrTheOther "foo" "bar"

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions