Since Scala 2.12 (or is it 2.13, can't be sure), the compiler can infer latent type arguments across multiple methods:
def commutative[
A,
B
]: ((A, B) => (B, A)) = {???} // implementing omitted
val a = (1 -> "a")
val b = commutative.apply(a)
The last line successfully inferred A = Int, B = String, unfortunately, this requires an instance a: (Int, String) to be given.
Now I'd like to twist this API for a bit and define the following function:
def findApplicable[T](fn: Any => Any)
Such that findApplicable[(Int, String)](commutative) automatically generate the correct function specialised for A = Int, B = String. Is there a way to do it within the language's capability? Or I'll have to upgrade to scala 3 to do this?
UPDATE 1 it should be noted that the output of commutative can be any type, not necessarily a Function2, e.g. I've tried the following definition:
trait SummonedFn[-I, +O] extends (I => O) {
final def summon[II <: I]: this.type = this
}
Then redefine commutative to use it:
def commutative[
A,
B
]: SummonedFn[(A, B), (B, A)] = {???} // implementing omitted
val b = commutative.summon[(Int, String)]
Oops, this doesn't work, type parameters don't get equal treatment like value parameters
If at some point some call-site knows the types of arguments (they aren't actually
Any => Any) it is doable using type classes:At call site:
However, this way you have to pass both
Inas well asOutas type parameters. If there are multiple possibleOuts for a singleIntype, then there is not much you can do.But if you want to have
Inputtype =>Outputtype implication, you can use dependent types:Call site:
That's how you can solve the issue when you know the exact input type. If you don't know it... then you cannot use compiler (neither in Scala 2 nor in Scala 3) to generate this behavior as you have to implement this functionality using some runtime reflection, e.g. checking types using
isInstanceOf, casting to some assumed types and then running predefined behavior etc.