ComposablePredicate.java

package org.klojang.check.types;

import org.klojang.check.Check;
import org.klojang.check.CommonChecks;

import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.function.Supplier;

import static org.klojang.check.types.Private.testAgainstArray;

/**
 * An extension of {@link Predicate} that acts as a bridge between {@code Predicate} and the relational
 * interfaces in this package. It enables the assembly of new tests from any number of instances of
 * {@link Predicate}, {@link IntPredicate}, {@link Relation}, {@link IntRelation} and {@link IntObjRelation}.
 *
 * <h2>AND vs. OR Compositions</h2>
 *
 * <p>Generally, you will have more use for compositions expressing a logical
 * disjunction (OR), because the chain of checks following {@link Check#that(Object) Check.that(...)} already
 * constitutes a logical conjunction (AND). For example, the following statement:
 *
 * <blockquote><pre>{@code
 * Check.that(numChairs).is(positive()).is(lt(), 4).is(even());
 * }</pre></blockquote>
 *
 * <p>requires the number of chairs to be positive <b>and</b> less than four  <b>and</b> even. If the number
 * of chairs needs to pass just one of these tests, write:
 *
 * <blockquote><pre>{@code
 * Check.that(numChairs).is(positive().orElse(lt(), 4).orElse(even()));
 * }</pre></blockquote>
 *
 * <p>Nevertheless, you might still want to use the {@code and()} methods for conciseness:
 *
 * <blockquote><pre>{@code
 * Check.that(string).is(notNull().and(hasSubstring(), allOf(), "to", "be", "or", "not"));
 * // is equivalent to:
 * Check.that(string).is(notNull())
 *    .is(hasSubstring(), "to")
 *    .is(hasSubstring(), "be")
 *    .is(hasSubstring(), "or")
 *    .is(hasSubstring(), "not")
 * }</pre></blockquote>
 *
 * <p>(See {@link Quantifier} for the {@code allOf()} argument.)
 *
 * <h2>Validating Interrelated Values</h2>
 *
 * <p>Sometimes, an argument, field or variable cannot be tested in isolation. Its
 * validity depends on the value of another argument, field or variable:
 *
 * <blockquote><pre>{@code
 * Check.that(engine.ready()).is(yes().or(buffer.size(), eq(), 0);
 * }</pre></blockquote>
 *
 * <p>In the above example, the engine only needs to be ready if there is more data
 * in the buffer.
 *
 * <p>Notice that the second check continues nicely in the idiom of Klojang Check,
 * even though it is now just syntactic sugar. Depending on your taste you can also just write:
 *
 * <blockquote><pre>{@code
 * Check.that(engine.ready()).is(yes().or(buffer.size() == 0);
 * }</pre></blockquote>
 *
 * <h2>Generics</h2>
 *
 * <p>Even though the type parameter for {@code ComposablePredicate} is {@code <T>},
 * the type parameter for the predicates and relations passed to the {@code and()} and {@code or()} methods is
 * simply {@code <?>}. This allows checks like {@link CommonChecks#notNull() notNull()} and
 * {@link CommonChecks#notEmpty() notEmpty()}, which can be applied to any non-primitive type, to be followed
 * by checks that can only be applied to a specific type. For example, the following code would <i>not</i>
 * compile if the argument to {@code andAlso()} were {@code Predicate<? super T>} instead of
 * {@code Predicate<?>}:
 *
 * <blockquote><pre>{@code
 * Check.that(file).is(empty().andAlso(writable()));
 * }</pre></blockquote>
 *
 * <p>The downside is that it is easier for a composition of tests to harbor a type
 * error without the compiler noticing it, resulting in a {@link ClassCastException} at runtime. For example,
 * the following nonsensical statement compiles just fine:
 *
 * <blockquote><pre>{@code
 * Check.that(list).is(empty().andAlso(writable()));
 * }</pre></blockquote>
 *
 * <p> In addition, when using lambdas, you will now have to specify the type of the
 * lambda parameter:
 *
 * <blockquote><pre>{@code
 * Check.that(file).is(empty().andAlso(f -> f.canWrite())); // WON'T COMPILE!!
 * Check.that(file).is(empty().andAlso((File f) -> f.canWrite())); // OK
 * }</pre></blockquote>
 *
 * <p>If you are not comfortable with this, you can instead use the
 * {@link #orThat(Object, Predicate) orThat()} method and repeat the argument for every call to
 * {@code orThat()}:
 *
 * <blockquote><pre>{@code
 * Check.that(list).is(empty().orThat(list, contains(), "foo"));
 * }</pre></blockquote>
 *
 * <p>Note, however, that the {@code orThat()} method is primarily meant to test <i>different</i>
 * (but interrelated) values.
 *
 * @param <T> the type of the value being tested
 * @see Relation
 * @see IntRelation
 * @see IntObjRelation
 * @see ObjIntRelation
 */
@SuppressWarnings({"unchecked", "rawtypes"})
@FunctionalInterface
public interface ComposablePredicate<T> extends Predicate<T> {

  /**
   * Returns the negation of this predicate.
   *
   * @param <U> the type of the value that is tested by the returned {@code ComposablePredicate}. Note that in
   *            actual fact, that really is the type of the value being tested by <i>this</i>
   *            {@code ComposablePredicate}.
   * @return the negation of this predicate
   * @see Predicate#negate()
   */
  default <U> ComposablePredicate<U> negated() {
    return x -> !meFirst(x);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test or the specified test. Note that this method is meant to be "just another
   * overload" or the other {@code or()} methods in this interface, except that in this case we would be
   * overriding {@link Predicate#or(Predicate)}. To avoid confusion and unintended behavior, it is best to
   * keep the two methods separate.
   *
   * @param test the test to combine this test with
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> orElse(Predicate<?> test) {
    return x -> meFirst(x) || ((Predicate) test).test(x);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test or if it has the specified relation to the specified value.
   *
   * <blockquote><pre>{@code
   * Check.that("foo bar").is(empty().or(hasSubstring(), "foo"));
   * }</pre></blockquote>
   *
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation, with the value of this {@code ComposablePredicate}
   *                 now becoming the subject of that relation
   * @param <O>      the type of the object of the provided {@code Relation}
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <O, V> ComposablePredicate<V> or(Relation<?, O> relation, O object) {
    return x -> meFirst(x) || ((Relation) relation).exists(x, object);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test or if it has a particular relation to the specified set of values.
   *
   * @param relation   the relationship test to combine this test with
   * @param quantifier a logical quantifier modulating the relationship
   * @param objects    the set of values to test the value against
   * @param <O>        the type of the object of the relation
   * @param <P>        the type of the values fed as "objects" into the relation
   * @param <V>        the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                   that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                   {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <O, P extends O, V> ComposablePredicate<V> or(Relation<V, O> relation,
      Quantifier quantifier,
      P... objects) {
    return x -> meFirst(x) || testAgainstArray(x, relation, quantifier, objects);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if <i>another</i> value ({@code subject}) has a particular
   * relation to the specified set of values.
   *
   * @param subject    the subject of the specified {@code Relation}
   * @param relation   the relationship test to combine this test with
   * @param quantifier a logical quantifier modulating the relationship
   * @param objects    the set of values to test the subject against
   * @param <S>        the type of the subject of the relation
   * @param <O>        the type of the object of the relation
   * @param <P>        the type of the values fed as "objects" into the relation
   * @param <V>        the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                   that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                   {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <S, O, P extends O, V> ComposablePredicate<V> or(S subject,
      Relation<S, O> relation,
      Quantifier quantifier,
      P... objects) {
    return x -> meFirst(x) || testAgainstArray(subject, relation, quantifier, objects);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test and if <i>another</i> value ({@code subject}) has a particular
   * relation to the specified set of values.
   *
   * @param subject    the subject of the relation
   * @param relation   the relationship test to combine this test with
   * @param quantifier a logical quantifier modulating the relationship
   * @param objects    the set of values to test the subject against
   * @param <V>        the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                   that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                   {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> or(int subject,
      IntRelation relation,
      Quantifier quantifier,
      int... objects) {
    return x -> meFirst(x) || testAgainstArray(subject, relation, quantifier, objects);
  }

  /**
   * Returns a new test combining this test with the specified free-form test. A value will pass the new test
   * if it passes <i>this</i> test or if the provided expression evaluates to {@code true}.
   *
   * @param test the boolean expression to evaluate if the value fails to pass this test
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified free-form test
   */
  default <V> ComposablePredicate<V> or(boolean test) {
    return x -> meFirst(x) || test;
  }

  /**
   * Returns a new test combining this test with the free-form test supplied by the specified
   * {@code Supplier}. A value will pass the new test if it passes
   * <i>this</i> test or if the expression supplied by the {@code Supplier}
   * evaluates to {@code true}. The supplier's {@link Supplier#get() get()} method will only be called if the
   * value fails to pass this test. Useful if evaluating the expression could be expensive.
   *
   * @param test the supplier of a boolean expression
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified free-form test
   */
  default <V> ComposablePredicate<V> or(Supplier<Boolean> test) {
    return x -> meFirst(x) || test.get();
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test or the negation of the specified test.
   *
   * @param test the test to combine this test with
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> orNot(Predicate<?> test) {
    return x -> meFirst(x) || !((Predicate) test).test(x);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test or if it does not have the specified relation to the specified value.
   *
   * @param relation the relationship test to combine this test with
   * @param object   the object of the provided {@code Relation}, with the value of
   *                 <i>this</i> {@code ComposablePredicate} now becoming the <i>subject</i> of
   *                 that relation
   * @param <O>      the type of the object of the provided {@code Relation}
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <O, V> ComposablePredicate<V> orNot(Relation<?, O> relation, O object) {
    return x -> meFirst(x) || !((Relation) relation).exists(x, object);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if another value manages to pass the other test.
   *
   * <blockquote><pre>{@code
   * Check.that(file1).is(readable().orThat(file2, writable()));
   * }</pre></blockquote>
   *
   * @param value the value to be tested by the specified test
   * @param test  the test to combine this test with
   * @param <U>   the type of the value being tested by the specified predicate
   * @param <V>   the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *              in actual fact, that really is the type of the value being tested by <i>this</i>
   *              {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <U, V> ComposablePredicate<V> orThat(U value, Predicate<U> test) {
    return x -> meFirst(x) || test.test(value);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if another value manages to pass the other test.
   *
   * <blockquote><pre>{@code
   * Check.that(file1).is(readable().orThat(file2, writable()));
   * }</pre></blockquote>
   *
   * @param value the value to be tested by the specified test
   * @param test  the test to combine this test with
   * @param <V>   the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *              in actual fact, that really is the type of the value being tested by <i>this</i>
   *              {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> orThat(int value, IntPredicate test) {
    return x -> meFirst(x) || test.test(value);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if another value manages to pass the other test.
   *
   * @param subject  the subject of the specified relation
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation
   * @param <S>      the type of the subject of the specified relation
   * @param <O>      the type of the object of the specified relation
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <S, O, V> ComposablePredicate<V> orThat(S subject,
      Relation<S, O> relation,
      O object) {
    return x -> meFirst(x) || relation.exists(subject, object);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if another value manages to pass the other test.
   *
   * @param subject  the subject of the specified relation
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> orThat(int subject,
      IntRelation relation,
      int object) {
    return x -> meFirst(x) || relation.exists(subject, object);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if another value manages to pass the negation of the other
   * test.
   *
   * <blockquote><pre>{@code
   * Check.that(file1).is(readable().orThat(file2, writable()));
   * }</pre></blockquote>
   *
   * @param value the value to be tested by the specified test
   * @param test  the test to combine this test with
   * @param <U>   the type of the value being tested by the specified predicate
   * @param <V>   the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *              in actual fact, that really is the type of the value being tested by <i>this</i>
   *              {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <U, V> ComposablePredicate<V> orNot(U value, Predicate<U> test) {
    return x -> meFirst(x) || !test.test(value);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test or if another value manages to pass the negation of the other
   * test.
   *
   * @param subject  the subject of the specified relation
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation
   * @param <S>      the type of the subject of the specified relation
   * @param <O>      the type of the object of the specified relation
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <S, O, V> ComposablePredicate<V> orNot(S subject, Relation<S, O> relation, O object) {
    return x -> meFirst(x) || !relation.exists(subject, object);
  }

  //////////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////// [AND methods] ////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes both this test and the specified test.
   *
   * @param test the test to combine this test with
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> andAlso(Predicate<?> test) {
    return x -> meFirst(x) && ((Predicate) test).test(x);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test and if it has the specified relation to the specified value.
   *
   * @param relation the relationship test to combine this test with
   * @param object   the object of the relation, with the value being tested now becoming the subject of the
   *                 relation
   * @param <O>      the type of the object of the provided {@code Relation}
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <O, V> ComposablePredicate<V> andAlso(Relation<?, O> relation, O object) {
    return x -> meFirst(x) && ((Relation) relation).exists(x, object);
  }

  /**
   * Returns a new test combining this test with the specified free-form test. A value will pass the new test
   * if it passes <i>this</i> test and if the provided expression evaluates to {@code true}.
   *
   * @param test the boolean expression to evaluate if the value fails to pass this test
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified free-form test
   */
  default <V> ComposablePredicate<V> and(boolean test) {
    return x -> meFirst(x) && test;
  }

  /**
   * Returns a new test combining this test with the free-form test supplied by the specified
   * {@code Supplier}. A value will pass the new test if it passes
   * <i>this</i> test and if the expression supplied by the {@code Supplier}
   * evaluates to {@code true}. The supplier's {@link Supplier#get() get()} method will only be called if the
   * value passes this test. Useful if evaluating the boolean expression could be expensive.
   *
   * @param test the supplier of a boolean expression
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified free-form test
   */
  default <V> ComposablePredicate<V> and(Supplier<Boolean> test) {
    return x -> meFirst(x) && test.get();
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test and if it has a particular relation to the specified set of values.
   *
   * @param relation   the relationship test to combine this test with
   * @param quantifier a logical quantifier modulating the relationship
   * @param objects    the set of values to test the value against
   * @param <O>        the type of the object of the relation
   * @param <P>        the type of the values fed as "objects" into the relation
   * @param <V>        the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                   that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                   {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <O, P extends O, V> ComposablePredicate<V> and(Relation<V, O> relation,
      Quantifier quantifier,
      P... objects) {
    return x -> meFirst(x) && testAgainstArray(x, relation, quantifier, objects);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test and if <i>another</i> value ({@code subject}) has a particular
   * relation to the specified set of values.
   *
   * @param subject    the subject of the specified {@code Relation}
   * @param relation   the relationship test to combine this test with
   * @param quantifier a logical quantifier modulating the relationship
   * @param objects    the set of values to test the subject against
   * @param <S>        the type of the subject of the relation
   * @param <O>        the type of the object of the relation
   * @param <P>        the type of the values fed as "objects" into the relation
   * @param <V>        the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                   that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                   {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <S, O, P extends O, V> ComposablePredicate<V> and(S subject,
      Relation<S, O> relation, Quantifier quantifier, P... objects) {
    return x -> meFirst(x) && testAgainstArray(subject, relation, quantifier, objects);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test and if <i>another</i> value ({@code subject}) has a particular
   * relation to the specified set of values.
   *
   * @param subject    the subject of the relation
   * @param relation   the relationship test to combine this test with
   * @param quantifier a logical quantifier modulating the relationship
   * @param objects    the set of values to test the subject against
   * @param <V>        the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                   that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                   {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> and(int subject,
      IntRelation relation, Quantifier quantifier, int... objects) {
    return x -> meFirst(x) && testAgainstArray(subject, relation, quantifier, objects);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes both this test and the negation of the specified test.
   *
   * @param test the test to combine this test with
   * @param <V>  the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *             in actual fact, that really is the type of the value being tested by <i>this</i>
   *             {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> andNot(Predicate<?> test) {
    return x -> meFirst(x) && !((Predicate) test).test(x);
  }

  /**
   * Returns a new test combining this test and the specified test. A value will pass the new test if it
   * passes <i>this</i> test and if it does not have the specified relation to the specified value.
   *
   * @param relation the relationship test to combine this test with
   * @param object   the object of the relation, with the value being tested now becoming the subject of the
   *                 relation
   * @param <O>      the type of the object of the provided {@code Relation}
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <O, V> ComposablePredicate<V> andNot(Relation<?, O> relation, O object) {
    return x -> meFirst(x) && !((Relation) relation).exists(x, object);
  }


  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes <i>this</i> test and if another value pass another
   * test.
   *
   * <blockquote><pre>{@code
   * Check.that(file1).is(readable().andThat(file2, writable()));
   * }</pre></blockquote>
   *
   * @param value the value to be tested by the specified test
   * @param test  the test to combine this test with
   * @param <U>   the type of the value being tested by the specified predicate
   * @param <V>   the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *              in actual fact, that really is the type of the value being tested by <i>this</i>
   *              {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <U, V> ComposablePredicate<V> andThat(U value, Predicate<U> test) {
    return x -> meFirst(x) && test.test(value);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes <i>this</i> test and if another value pass another
   * test.
   *
   * <blockquote><pre>{@code
   * Check.that(file1).is(readable().andThat(file2, writable()));
   * }</pre></blockquote>
   *
   * @param value the value to be tested by the specified test
   * @param test  the test to combine this test with
   * @param <V>   the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *              in actual fact, that really is the type of the value being tested by <i>this</i>
   *              {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> andThat(int value, IntPredicate test) {
    return x -> meFirst(x) && test.test(value);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes <i>this</i> test and if another value pass another
   * test.
   *
   * @param subject  the subject of the specified relation
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation
   * @param <S>      the type of the subject of the specified relation
   * @param <O>      the type of the object of the specified relation
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <S, O, V> ComposablePredicate<V> andThat(S subject,
      Relation<S, O> relation,
      O object) {
    return x -> meFirst(x) && relation.exists(subject, object);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes <i>this</i> test and if another value pass another
   * test.
   *
   * @param subject  the subject of the specified relation
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <V> ComposablePredicate<V> andThat(int subject,
      IntRelation relation,
      int object) {
    return x -> meFirst(x) && relation.exists(subject, object);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test and if another value manages to pass the negation of the other
   * test.
   *
   * <blockquote><pre>{@code
   * Check.that(file1).is(readable().andThat(file2, writable()));
   * }</pre></blockquote>
   *
   * @param value the value to be tested by the specified test
   * @param test  the test to combine this test with
   * @param <U>   the type of the value being tested by the specified predicate
   * @param <V>   the type of the value that is tested by the returned {@code ComposablePredicate}. Note that
   *              in actual fact, that really is the type of the value being tested by <i>this</i>
   *              {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <U, V> ComposablePredicate<V> andNot(U value, Predicate<U> test) {
    return x -> meFirst(x) && !test.test(value);
  }

  /**
   * Returns a new test combining this test and the specified test. It combines two checks on two different
   * values. A value will pass the new test if it passes
   * <i>this</i> test and if another value manages to pass the negation of the other
   * test.
   *
   * @param subject  the subject of the specified relation
   * @param relation the relationship test to combine this test with
   * @param object   the object of the specified relation
   * @param <S>      the type of the subject of the specified relation
   * @param <O>      the type of the object of the specified relation
   * @param <V>      the type of the value that is tested by the returned {@code ComposablePredicate}. Note
   *                 that in actual fact, that really is the type of the value being tested by <i>this</i>
   *                 {@code ComposablePredicate}.
   * @return a new test combining this test and the specified test
   */
  default <S, O, V> ComposablePredicate<V> andNot(S subject,
      Relation<S, O> relation,
      O object) {
    return x -> meFirst(x) && !relation.exists(subject, object);
  }

  private <V> boolean meFirst(V v) {
    return ComposablePredicate.this.test((T) v);
  }

}