Sunday, October 31, 2010

In my current F# project, I’ve employed a very simple library to support basic contract checking. It’s not fantastically clever, but I thought I’d post it here in case others find it useful.

To use the library, pipe values into the various functions of the “Is” module. For example…

let jz : OpcodeRoutine = fun (i, proc) ->
  i.Operands.Length |> Is.EqualTo 1
  i.HasBranchOffset |> Is.True

  let x = i.Operands.[0] |> proc.GetOperandValue
  let res = x = 0us
  if i.BranchOffset.Condition = res then
    proc.Branch i.BranchOffset

If either of the two preconditions highlighted above fail, a ContractFailureException will be thrown.

The full module is below. Again, the following code isn’t exactly rocket science, but I’ve found it dead useful, and you might, too.

exception ContractFailureException of string

[<RequiredModuleAccess>]
module Is =

  let inline private fail message =
    raise <| ContractFailureException(message)

  let inline private failf fmt =
    Printf.ksprintf fail fmt

  let inline True condition =
    if condition <> true then
      fail "condition should be true."

  let inline False condition =
    if condition = true then
      fail "condition should be false."

  let inline Null obj =
    if obj <> null then
      fail "obj should be null."

  let inline Some obj =
    match obj with
    | Some(_) -> ()
    | None -> fail "obj should be Some."

  let inline None obj =
    match obj with
    | Some(_) -> fail "obj should be None."
    | None -> ()

  let inline NotNull obj =
    if obj = null then
      fail "obj should not be null."

  let inline EqualTo expected value =
    if value <> expected then
      failf "value should be equal to %A." expected

  let inline NotEqualTo expected value =
    if value = expected then
      failf "value should not be equal to %A." expected

  let inline LessThan high value =
    if value >= high then
      failf "value should be less than %A." high

  let inline LessThanOrEqualTo high value =
    if value > high then
      failf "value should be less than or equal to %A." high

  let inline GreaterThan low value =
    if value <= low then
      failf "value should be greater than %A." low

  let inline GreaterThanOrEqualTo low value =
    if value < low then
      failf "value should be greater than or equal to %A." low

  let inline InRange low high value =
    if value < low || value > high then
      failf "value should be in range %A to %A." low high

  let inline NotInRange low high value =
    if value >= low && value <= high then
      failf "value should not be in range %A to %A." low high

  let inline Empty (value : seq<_>) =
    if not (value |> Seq.isEmpty) then
      fail "value should be empty."

  let inline NotEmpty (value : seq<_>) =
    if value |> Seq.isEmpty then
      fail "value should not be empty."

  let inline OfType<'a> (value : obj) =
    match value with
    | :? 'a -> ()
    | _ -> failf "value should be of type %s." typeof<'a>.FullName

  let inline NotOfType<'a> (value : obj) =
    match value with
    | :? 'a -> failf "value should not be of type %s." typeof<'a>.FullName
    | _ -> ()

Enjoy!

posted on Sunday, October 31, 2010 10:26:02 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]

kick it on DotNetKicks.com