Scala: Is it possible to constrain a type parameter to be non abstract?

994 views Asked by At

Scala: Is it possible to constrain a type parameter to be non abstract?

Are any other constraints possible except view bounds, upper bounds and lower bounds for type parameters and abstract type members? In C# for example, which I'm familiar with, you have the additional generic constraints:

where T: Class //Not sure if this covered in Scala by T<: AnyRef

where T: interface

where T: struct

where U: T //naked type constraint

where T: new () //This ensures that a type parameter is non-abstract and allows one to instantiate an object of the type in the generic class.

The last one is particularly important as it allows you to construct your unknown type, although its a shame you can only proscribe a parameterless constructor.

Can =:= <:< and <%< only be used on method parameters?

In response to the comments, the immediate trigger for the question was the need for a "T: new()" restraint or some equivalent mechanism.

class ExampleClass[T <: AnyRef] {
  val example: T = new T()//Won't compile as the compiler  
} //doesn't know if such a constructor exists

The uses of some of the C# constraints are particular to the needs of C#. For example one restraint that you don't have in C# that people are always wanting is "T: numericType" That issue is already solved in Scala. I'm still very much boot strapping my way up the Scala language, so aside from the above, I was just trying to clarify exactly what tools are and are not available to me in this facet of Scala syntax, even though I don't know yet exactly how I might want to use them in the Scala context.

I'm not sure if this is fully related but sometimes it seems the compiler (Eclipse 2.1.0.M1 with Eclipse 3.7.2) won't let me instantiate collections of unknown element type. The following code now seems to compiles fine. So I'd like to know what the rules are:

abstract class Descrip [T <: DTypes]()
{      
  val hexs: MutableList[T#HexT] = new  MutableList[T#HexT] //compiles fine
  val sides: MutableList[T#SideT] = new MutableList[T#SideT] //compiles fine
}
1

There are 1 answers

2
gerferra On BEST ANSWER

The need of new T() is normally resolved by using Manifests. For example this code compiles:

class ExampleClass[T: Manifest] {
  val example: T = manifest[T].erasure.newInstance().asInstanceOf[T]
}

The drawback is that if the T for which ExampleClass is instantiated doesn't have a no-arg constructor it will fail at runtime...

Regarding Numeric, Ordering, etc., they are type classes and are part of the standard library, not part of the language. You can build your own type classes. The case of Manifest is special because it do have support from the language to provide the implicit object.