2

I am trying to write a query library for Scala. Here is the code so far:

class Query[TElement](source: Traversable[TElement]) {
    def join[TOther](other: Traversable[TOther]) = new {
        def on[TKey](keySelector1: TElement => TKey) = new {
            def equals(keySelector2: TOther => TKey) = new {
                def into[TResult](resultSelector: (TElement, TOther) => TResult): Query[TResult] = {
                    val map = source.map(e => (keySelector1(e), e)).toMap
                    val results = other
                        .map(e => (keySelector2(e), e))
                        .filter(p => map.contains(p._1))
                        .map(p => (map(p._1), p._2))
                        .map(p => resultSelector(p._1, p._2))
                    new Query[TResult](results)
                }
            }
        }
    }
}

object Query {
    def from[TElement](source: Traversable[TElement]): Query[TElement] = {
        new Query[TElement](source)
    }
}

...

val results = Query.from(users)
    .join(accounts).on(_.userId).equals(_.ownerUserId).into((_, _))

I get the following error when I go to compile:

error: missing parameter type for expanded function ((x$2) => x$2.ownerUserId)

I am a little confused why I would get this error on the non-generic function equals. Its generic parameters come from the outer scope, I'd think. I know to fix it I have to explicitly say what the parameter type is by writing (a: Account) => a.ownerUserId. However, I am trying to make it a pretty fluent library, and this is making it messy.

0

1 Answer 1

2

The problem is quite simple. There is an ambiguity with the existing method equals that is inherited from Any. Simple example:

scala> class X[A, B] { def equals(f: A => B) = f }
defined class X

scala> val x = new X[Int, String]
x: X[Int,String] = X@52d455b8

scala> x.equals((x: Int) => x.toString)
res0: Int => String = <function1>

scala> x.equals((x: String) => x.toString) // uh-oh
res1: Boolean = false

As one can see in the last example, when the wrong function type is passed, the compiler has to choose def equals(Any): Boolean. When you don't specify any type, the compiler has to infer one, which it can't do in the example.

Simply rename your method to something else and the problem is gone.

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

1 Comment

I see. So this is just a matter of resolving a method overload ambiguity. It would be nice if the error message made that more clear.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.