class UdfIndex {

  T getFunction(final List<SqlType> arguments) {
    final List<Node> candidates = new ArrayList<>();

    // first try to get the candidates without any implicit casting
    getCandidates(arguments, 0, root, candidates, new HashMap<>(), false);
    final Optional<T> fun = candidates
        .stream()
        .max(Node::compare)
        .map(node -> node.value);

    if (fun.isPresent()) {
      return fun.get();
    } else if (!supportsImplicitCasts) {
      throw createNoMatchingFunctionException(arguments);
    }

    // if none were found (candidates is empty) try again with
    // implicit casting
    getCandidates(arguments, 0, root, candidates, new HashMap<>(), true);
    return candidates
        .stream()
        .max(Node::compare)
        .map(node -> node.value)
        .orElseThrow(() -> createNoMatchingFunctionException(arguments));
  }

    UdfIndex(final String udfName, final boolean supportsImplicitCasts);

}