How do I use Predicate and Assessor for testing conditions?

← Generics · Ref: Q709

Predicate and Assessor are the Boolean-returning single-parameter function types. They test a condition on value 't'.

PREDICATE IS PURE

Predicate of T takes 't' and returns 'r' as Boolean. Being pure, it is a stateless test:

  check <- () is Predicate of Integer as pure function
    r: t > 0

Always gives the same result for the same input.

ASSESSOR IS IMPURE

Assessor of T has the same signature but is NOT pure:

  logCheck <- () is Assessor of Integer as function
    stdout <- Stdout()
    stdout.println(`Checking: ${t}`)
    r: t > 0

Assessor allows side effects during evaluation.

STREAM FILTER PATTERN

Predicates work naturally as stream filter conditions.

PARAMETER USAGE

Pass Predicate or Assessor to control purity:

  testValue() as pure
    -> item as Integer, check as Predicate of Integer
    <- result as Boolean: check(item)

See Q54 for pure vs impure concepts. See Q89 for stream pipeline operations. See Q235 for stream operations reference.

Example

defines module qa.genericsdeep.predicateassessor

  defines function

    <?-
      Helper that uses a Predicate to test a value.
      Pure context — only pure Predicates accepted.
    -?>
    testValue() as pure
      ->
        item as Integer
        check as Predicate of Integer
      <- result as Boolean: check(item)

    <?-
      Helper that uses an Assessor to test a value.
      Impure context — Assessor can have side effects.
    -?>
    assessValue()
      ->
        item as Integer
        check as Assessor of Integer
      <- result as Boolean: check(item)

  defines program

    PredicateAssessorDemo()
      stdout <- Stdout()

      //Predicate: pure, stateless Boolean test
      //Body uses 't' for input, 'r' for return — from Predicate's signature
      positiveCheck <- () is Predicate of Integer as pure function
        r: t > 0

      stdout.println(`Is 42 positive: ${testValue(42, positiveCheck)}`)
      stdout.println(`Is -1 positive: ${testValue(-1, positiveCheck)}`)

      //Assessor: impure, can log during evaluation
      logCheck <- () is Assessor of Integer as function
        stdout <- Stdout()
        stdout.println(`Assessing: ${t}`)
        r: t > 0

      result <- assessValue(99, logCheck)
      stdout.println(`Assessment result: ${result}`)

Common mistakes

E05150 — Predicate is pure — dynamic functions extending Predicate 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 Predicate of Integer as function

Correct:

() is Predicate of Integer as pure function
Other ways to ask this
  • What is the difference between Predicate and Assessor in EK9?
  • How do I create a Predicate of Integer for filtering?
  • When should I use Assessor instead of Predicate?

Coming from another language?

Java: java.util.function.Predicate<T> — no purity distinction, can have side effects, supports and/or/negate composition. Kotlin: (T) -> Boolean — no pure/impure variants. Rust: Fn(&T) -> bool (pure) vs FnMut(&T) -> bool (stateful). Go: func(T) bool — no purity. C#: Predicate<T> or Func<T, bool> — no purity concept. EK9: Predicate (pure, stateless test) vs Assessor (impure, can track state) — compile-time enforced.

Keywords: test, function-type, pure, stream, filter, predicate, condition, generic, side-effect, boolean, assessor, impure