transparent inline def eval[A, B](f: A => B, x: A): Any =
inline f match
case g: (A => Future[?]) => g(x).value.get.get
case _ => f(x)
eval((x: Int) => Future.successful(x), 10)
eval((x: Int) => x + 1, 10)
Both expressions have type Int, which is what I want. In my actual case, however, f has type A ?=> B instead of A => B. Can I still match on f to branch at compile-time depending on the type B?
The main issue seems to be that there’s not really a good generally applicable way to just use f in an expression when f has type A ?=> Bwithout meaning to implicitly invoke f.
But this workaround worked for me:
transparent inline def eval[A, B](f: A ?=> B, x: A): Any =
val f0 = a => f(using a)
inline f0 match
case g: (A => Future[?]) => g(x).value.get.get
case _ => f0(x)
eval(Future.successful(summon[Int]), 10)
eval(summon[Int] + 1, 10)
Excellent! That should work. I’ll probably need intermediate functions for what I want to do, and those can be in terms of A => B as long as A ?=> B stays in the user-level interface. Thanks a lot.
Yeah I thought at least inline (f: A ?=> B) match should work but even then the compiler complains about not finding an implicit A. That might actually be a bug, given that val g: A ?=> B = f does work.
I was able to accomplish what I wanted, but I’m getting a spurious warning on f0 being unused. Unfortunately, I’ve not been able to reproduce it on Scastie. It seems to be triggered by compiling one of my tests, as if something has become unused after inlining, but I can’t figure out where exactly.
It’s a real warning (using -Wunused:all). I don’t know the fancy compiler options that would let me investigate further, e.g., to find the specific test that triggers the warning. With it, I might be able to recreate the issue for a bug report.