How do I use BiPredicate and BiAssessor to test two values?

← Generics · Ref: Q712

BiPredicate and BiAssessor are the Boolean-returning two-parameter function types. They test a condition involving values 't' and 'u'.

BIPREDICATE IS PURE

BiPredicate of (T, U) takes parameters 't' and 'u' and returns 'r' as Boolean. Being pure, the test is stateless:

  check <- () is BiPredicate of (String, Integer) as pure function
    r: length t > u

BIASSESSOR IS IMPURE

BiAssessor of (T, U) has the same signature but is NOT pure:

  logCheck <- () is BiAssessor of (String, Integer) as function
    stdout <- Stdout()
    stdout.println(`Assessing: ${t} vs ${u}`)
    r: length t > u

USE CASES

BiPredicate: Pure comparison, matching, or relationship testing.
BiAssessor: Testing with logging, metrics, or state-dependent checks.

See Q54 for pure vs impure concepts. See Q709 for single-parameter Predicate/Assessor.

Example

defines module qa.genericsdeep.bipredicatebiassessor

  defines function

    <?-
      Helper that applies a pure BiPredicate.
    -?>
    testPair() as pure
      ->
        text as String
        threshold as Integer
        check as BiPredicate of (String, Integer)
      <- result as Boolean: check(text, threshold)

    <?-
      Helper that applies an impure BiAssessor.
    -?>
    assessPair()
      ->
        text as String
        threshold as Integer
        check as BiAssessor of (String, Integer)
      <- result as Boolean: check(text, threshold)

  defines program

    BiPredicateBiAssessorDemo()
      stdout <- Stdout()

      //BiPredicate: pure, stateless test of two values
      //Body uses 't' and 'u' for inputs, 'r' for return
      lengthCheck <- () is BiPredicate of (String, Integer) as pure function
        r: length t > u

      stdout.println(`'Hello' longer than 3: ${testPair("Hello", 3, lengthCheck)}`)
      stdout.println(`'Hi' longer than 3: ${testPair("Hi", 3, lengthCheck)}`)

      //BiAssessor: impure, can log during assessment
      logCheck <- () is BiAssessor of (String, Integer) as function
        stdout <- Stdout()
        stdout.println(`Assessing: length of '${t}' vs ${u}`)
        r: length t > u

      result <- assessPair("Testing", 3, logCheck)
      stdout.println(`BiAssessor result: ${result}`)

Common mistakes

E05150 — BiPredicate is pure — dynamic functions extending BiPredicate must use 'as pure function', not just 'as function'. The compiler requires the purity of the implementation to match its pure super type. See ek9 -h E05150 for details.

Incorrect:

() is BiPredicate of (String, Integer) as function

Correct:

() is BiPredicate of (String, Integer) as pure function
Other ways to ask this
  • What is the difference between BiPredicate and BiAssessor?
  • How do I create a BiPredicate of (String, String)?
  • When should I use BiAssessor instead of BiPredicate?

Coming from another language?

Java: java.util.function.BiPredicate<T,U> — no purity distinction, supports and/or/negate. Kotlin: (T, U) -> Boolean — no pure/impure variants. Rust: Fn(&T, &U) -> bool vs FnMut(&T, &U) -> bool — structural. Go: func(T, U) bool — no purity. C#: Func<T1, T2, bool> — no purity concept. EK9: BiPredicate (pure) vs BiAssessor (impure) — compile-time enforced.

Keywords: biassessor, pure, bipredicate, function-type, comparison, test, side-effect, boolean, generic, impure, two-parameter