user48956
user48956

Reputation: 15820

How to use nested generics in scala

edit Simplified the example. Added more detail.

What I'd like is to do is compose a class with a method. The class has a type parameter of the form A[B], where A and B are abstract types (generic parameters), and its methods can work with objects of types A or B, or other types composed from A or B. For example, the class might have a method that takes an A[B] type object as a parameter, and return a B type object.

This kind of pattern is extremely common in say, the C++ standard template library.

Is this possible in scala?

In my example below, within ListDoer, A is the abstract type name ListT and B the abstract typename TElement. Later, I try to provide the concrete types, ListT[TElement] = MyList[Double]

class ListDoer[ ListT[TElement] ]
{
  // Processes abstract list type.                 
  def doIt( list:ListT[TElement] ) : TElement = { list.get(0) }   // TElement not found

  // Attempt 2:
  type L=ListT[TElement]               // TElement not found
  def doIt2( list:L ) : TElement ={ list.get(0) }   // TElement not found
}

// More concrete list type
class MyList[TElement]
{
   var None: TElement = _                         
   def get(i:Int): TElement = None   // placeholder               
   def put(i:Int, value:TElement): Unit = { }
}

// MyList[Double] is the concrete list type that doIt should take as a parameter
val doer2 = new ListDoer[ MyList[Double] ]   // MyList[Double] takes no parameters, expected one

val list1 = new MyList[Double]
doer2.doIt( list1 )         // Process list1. Should return list1.get(0)   

list.get(0) is a placeholder implementation for this example.

ListDoer class should not require any external types other than those provided as type parameters. (e.g. it should not be tied to a particular implementation of a list, or interfaces specified in any particular collections library). However, the above code is going to require that ListT[ElementT] has a method: get(Int):ElementT and cause ListDoer to fail to be instantiated is this is not met.

The above code looks reasonable to me (coming from a C++ background), but fails to compile in two places:

It this kind of nested use of generics permitted in scala?

Upvotes: 0

Views: 981

Answers (1)

Eugene Ryzhikov
Eugene Ryzhikov

Reputation: 17369

object XXX {

     class MyList[T] {
          var None: T = _
          def get(k: Int): T = None // placeholder               
          def put(k: Int, v: T): Unit = {}
     }

     class ListDoer[T] {

          // this defines the "wrapper" type 
          // which requires only get method to be there
          type W[T] = { def get(k: Int): T } 

          def doIt(list: W[T]): T = { 
               return null.asInstanceOf[T]
          } 
     }

     type L = Double
     val doer1 = new ListDoer[L] // L takes no parameters, expected one 
     val doer2 = new ListDoer[Double] // L takes no parameters, expected one

     val list1 = new MyList[Double]
     val list2 = List[L]()
     doer1.doIt(list1)

}

Upvotes: 2

Related Questions