Firstly, some background:
I'm currently writing a generic solver for a certain class of problems (specifically, a structural SVM solver) in Scala. In order to use this, the user has to implement an interface.
Consider a simplified version of the interface:
trait HelperFunctions[X, Y] {
def func1(x: X, y: Y): Y
def func2(y1: Y, y2: Y): Int
}
and a simple implementation:
object ImplFunctions extends HelperFunctions[Vector[Double], Double] {
def func1(x: Vector[Double], y: Double): Double = { ... }
def func2(y1: Double, y2: Double): Int = { .. }
}
(Note that the implementation has to be provided in form of an object.)
Now, the problem:
I need to write a diagnostic suite which aids the user to verify the sanity of his functions. An example sanity test would involve something like func1(..)
being positive for all x
and y
. For this, I set out by writing a BDD-style unit-tests using ScalaTest.
Note that the diagnostic suite should be generic, to work with any object which extends HelperFunctions[X, Y]
.
A high-level picture of how I planned to go about this: first providing all the sanity tests designed for generic X
and Y
. Then, the user merely replaces, say a ???
, with a ImplFunctions
and runs the suite.
But, turns out I didn't find an elegant approach to treat ImplFunctions
as a generic HelperFunctions[X, Y]
. Here's a taste of what I've tried so far:
import org.scalatest._
class ApplicationDiag extends FlatSpec {
// Option 1:
// Cast the ImplFunctions into a generic type
// ERROR: type mismatch; found : ImplFunctions.type, required : HelperFunctions[X, Y]
val helpers: HelperFunctions[X, Y] = ImplFunctions
// OR
def helpers[X, Y](): HelperFunctions[X, Y] = ImplFunctions
// Option 2: User fills up the right side, no type specified for the value
// WORKS. But, cannot explicitly state types
val helpers = ImplFunctions
"func1" should "be positive" in {
// ... the check as described previously
}
}
Due to the covariance nature, I imagine it should be possible to cast an instance of a type to its supertype. But, it seems to be tougher since this involves generics. Is there a clean way to do this?
Note: 1. I'm totally open to alternate designs for the diagnostic suite. 2. The real-world interface: HelperFunctions and a real-world application: ImplFunctions
+X
/-X
syntax. You shouldn't need to cast. – lmm