1

I define an enum that takes a method reference:

enum class Op(val param: (Expression<String>, String) -> Predicate) { GREATER_THAN(CriteriaBuilder::greaterThan) } 

There are two candidates in the CriteriaBuilder class, and the compiler can't figure out which one I mean ("Overload resolution ambiguity. All these functions match."):

<Y extends Comparable<? super Y>> Predicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y); <Y extends Comparable<? super Y>> Predicate greaterThan(Expression<? extends Y> x, Y y); 

Why can't Kotlin infer the right type? Clearly the first method is not possible. I can't figure out how to guide the compiler, casting it to the right type doesn't seem to work:

GREATER_THAN(CriteriaBuilder::greaterThan as (Expression<String>, String) -> Predicate) 

Compiler complains "Cannot choose among the following candidates without completing type inference".

3
  • Is there a particular reason you're using Java's BiFunction interface instead of a Kotlin function type (Expression<String>, String) -> Predicate? Commented Feb 24, 2022 at 9:52
  • Old habits, fixed! Commented Feb 24, 2022 at 9:57
  • Who is supposed to provide the CriteriaBuilder instance in your design? The definition of the enum itself, or the caller of Op.param? Commented Feb 24, 2022 at 10:03

1 Answer 1

3

Given the Javadoc of CriteriaBuilder, the method you're referring to is not static.

Since you're not providing an instance of CriteriaBuilder in your function reference, this means that CriteriaBuilder::greaterThan actually expects a receiver or parameter of type CriteriaBuilder in addition to the 2 arguments, which doesn't match the signature that you're expecting: (Expression<String>, String) -> Predicate.

If you want the caller of Op.param to provide the criteria builder instance, then I suggest to change Op.param's type to (CriteriaBuilder, Expression<String>, String) -> Predicate or CriteriaBuilder.(Expression<String>, String) -> Predicate - which would match the function reference CriteriaBuilder::greaterThan. The choice of which one to use depends on how you want to call it:

enum class Op(val param: CriteriaBuilder.(Expression<String>, String) -> Predicate) { GREATER_THAN(CriteriaBuilder::greaterThan) } // or enum class Op(val param: (CriteriaBuilder, Expression<String>, String) -> Predicate) { GREATER_THAN(CriteriaBuilder::greaterThan) } 

If you want to have the CriteriaBuilder "built-in" the enum, you can instantiate it up front, and then use your specific instance in the function reference:

val yourCriteriaBuilder: CriteriaBuilder = TODO("create it somehow") enum class Op(val param: (Expression<String>, String) -> Predicate) { GREATER_THAN(yourCriteriaBuilder::greaterThan) } 

I'm not familiar with the CriteriaBuilder API, so I'm not sure if this last option is actually desirable. You might want new instances each time instead - your call.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Joffrey for your detailed and thoughtful reply! I didn't know about the "CriteriaBuilder.(Expression<String>, String) -> Predicate" syntax, this is exactly what I need.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.