3

I'm creating some parameterized classes C[T] and I want to make some requirements of the characteristics of the type T to be able to be a parameter of my class. It would be simple if I just wanted to say that T inherited from traits or classes (as we do with Ordering). But I want it to implement some functions as well.

For example, I've seen that many pre-defined types implement MinValue and MaxValue, I would like my type T to implement these too. I've received some advice to just define an implicit function. But I wouldn't like that all the users were obliged to implement this function for these when it is already implemented. I could implement them at my code too, but it seems just to be a poor quick fix.

For example, when defining heaps, I would like to allowd users to construct a empty Heap. In these cases I want to inicialize value with the minimum value the type T could have. Obviously this code does not works.

class Heap[T](val value:T,val heaps:List[Heap[T]]){
    def this()=this(T.MinValue,List())
}

I also would love to receive some advice about really good online Scala 2.8 references.

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
Bruna
  • 366
  • 2
  • 15

2 Answers2

6

A bunch of things, all loosely related by virtue of sharing a few methods (though with different return types). Sure sounds like ad-hoc polymorphism to me!

roll on the type class...

class HasMinMax[T] {
  def maxValue: T
  def minValue: T
}

implicit object IntHasMinMax extends HasMinMax[Int] {
  def maxValue = Int.MaxValue
  def minValue = Int.MinValue
}

implicit object DoubleHasMinMax extends HasMinMax[Double] {
  def maxValue = Double.MaxValue
  def minValue = Double.MinValue
}

// etc

class C[T : HasMinMax](param : T) {
  val bounds = implicitly[HasMinMax[T]]
  // now use bounds.minValue or bounds.minValue as required
}

UPDATE

The [T : HasMinMax] notation is a context bound, and is syntactic sugar for:

class C[T](param : T)(implicit bounds: HasMinMax[T]) {
  // now use bounds.minValue or bounds.minValue as required
}
Kevin Wright
  • 49,540
  • 9
  • 105
  • 155
2

You can either use type bounds:

trait Base

class C[T <: Base]

enabling C to be parametrized with any type T which is a subtype of Base.

Or you can use implicit parameters to express requirements:

trait Requirement[T] {
  def requiredFunctionExample(t: T): T
}

class C[T](implicit req: Requirement[T])

Thus, objects of class C can only be constructed if there exists an implementation of the Requirement trait for the type T you wish to parametrize them with. You can place implementations of Requirement for different types T in, for instance, a package object, thus bringing them into scope whenever the corresponding package is imported.

axel22
  • 32,045
  • 9
  • 125
  • 137
  • Ok! But that's not what I'm looking for. I don't wanna redefine MinValue and MaxValue in a trait when it's already defined. More than that, I would like, Int, Double, Char... to be these parametre T but none of them extends the trait I'm creating. – Bruna Dec 02 '10 at 18:36
  • The problem is that `MinValue` and `MaxValue` do not have the same types for `Int`, `Char`, ..., they have different signatures, so they are different methods. This means you'd probably have to create a requirement trait with an abstract method returning, for instance, Any, and then redefine it for the base types. I hope I understood you correctly.. – axel22 Dec 02 '10 at 18:43