Danny Danny - 1 year ago 92
Scala Question

Scala type constraint of companion type

I want a class that has a function (which is contracted by a trait) available statically. Then I want a type parameterized method that takes such a type as its type parameter and accesses the contracted static function. (Yes I know the term static is Java not Scala but you know what I mean.)

The only way I know to have a static function in Scala is by having a companion object extend the trait. However doing that has to problems:

  1. I don't know how to constrain the type parameter such that it's companion object extends some trait.

  2. I don't know how I would access the static method being that the class is actually of a different type than its companion object.

This may be completely off but kinda what I want to do is:

MyTrait {
def MyFunction() : Any //some function

case class MyClass(i: Int)

object MyClass extends MyTrait {
def MyFunction() = {/*do stuff*/}

//need the type as a class not an object because I need it for a higher order function like this
def SomeFunctionHigherOrderFunction[T /*constrain T such that the companion object of T <: MyTrait*/](someFunc : Function1[T, Any]) : Unit {
val someStuff = T.MyFunction()
/*use someStuff in here*/

SomeFunctionHigherOrderFunction[T](/*provide a Function1[T, Any]*/);

Any ideas of the correct solution or some better ways of going about this problem?

Thanks in advance!

Answer Source

There is no way to do exactly this. One approach you can take is to pass the method in via implicits (this is also known as the typeclass approach). You'll need to parametrize your trait over T (even if you don't use it, T is used to resolve to the right implicit).

trait MyTrait[T] {
  def MyFunction() : Any //some function (usually you want to use `T` somehow)

Then, you declare your companion object to be implicit. Something like this

implicit object MyClass extends MyTrait[MyClass] {
  def MyFunction = ...

Or if you don't have anything else in that object, you could even do it just inline:

implicit val myTraitMyClass: MyTrait[MyClass] = new MyTrait[MyClass] {
  def MyFunction = ...

And use it via

def SomeHigherOrderFunction[T](someFunc : Function1[T, Any])(implicit o: MyTrait[T]): Unit {
  val someStuff = o.MyFunction()
   /*use someStuff in here*/