Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract Types / Type Parameters in Scala

Tags:

types

scala

I am trying to write some Scala code that needs to do something like:

class Test[Type] { 
   def main {
       SomeFunc classOf[Type]
       val testVal: Type = new Type()
    }
 }

and it's failing. I'm obviously not understanding something about Scala generic parameters. Clearly, the misunderstanding is that in C++, templates essentially function like string substitutions, so new Type() will work as long as the class being passed in has a default constructor. However, in Scala, types are different kinds of objects.

like image 510
bsdfish Avatar asked May 04 '09 06:05

bsdfish


People also ask

What are type parameters in Scala?

Methods in Scala can be parameterized by type as well as value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses. The method listOfDuplicates takes a type parameter A and value parameters x and length .

Which is known as the abstract data type in Scala?

sealed trait s (or sealed abstract class es) are also known as coproducts. case object s and Int , Double , String (etc) are known as values.

What is an abstract class in Scala?

In Scala, an abstract class is constructed using the abstract keyword. It contains both abstract and non-abstract methods and cannot support multiple inheritances. A class can extend only one abstract class.

What is the difference between a trait and an abstract class in Scala?

Trait supports multiple inheritance. Abstract Class supports single inheritance only. Trait can be added to an object instance. Abstract class cannot be added to an object instance.


1 Answers

As you point out, C++ has templates. In short, C++ says "there is a Test for all types T such that Test compiles." That makes it easy to implicitly add constraints on T, but on the down side they're implicit and may be hard for a user of your class to understand without reading code.

Scala's parametric polymorphism (aka generics) work much more like ML, Haskell, Java, and C#. In Scala, when you write "class Test[T]" you are saying "for all T there exists a type Test[T]" without constraint. That's simpler to reason about formally, but it does mean that you have to be explicit about constraints. For instance, in Scala you can say "class Test[T <: Foo]" to say that T must be a subtype of Foo.

C# has a way to add a constraint to T regarding constructors, but unfortunately Scala does not.

There are a couple of ways to solve your problem in Scala. One is typesafe but a bt more verbose. The other is not typesafe.

The typesafe way looks like

class Test[T](implicit val factory : () => T) {
  val testVal = factory
}

Then you can have a body of factories for types useful in your system

object Factories {
  implicit def listfact[X]() = List[X]()
  implicit def setfact[X]() = Set[X]()
  // etc
}

import Factories._
val t = new Test[Set[String]]

If users of your library need their own factories then they can add their own equivalent of the Factories object. One advantage to this solution is that anything with a factory can be used, whether or not there's a no-arg constructor.

The not-so-typesafe way uses reflection and a feature in Scala called manifests which are a way to get around a Java constraint regarding type erasure

 class Test[T](implicit m : Manifest[T]) {
   val testVal = m.erasure.newInstance().asInstanceOf[T]
 }

With this version you still write

class Foo
val t = new Test[Foo]

However, if there's no no-arg constructor available you get a runtime exception instead of a static type error

scala> new Test[Set[String]] 
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)
like image 83
James Iry Avatar answered Sep 17 '22 00:09

James Iry