Improving ugly parameter list on traits

Viewed 54

The problem I'm looking at involves defining a trait which has type parameters, where it's type parameters have type parameters where I need to know these types as well. For example, consider the following code:

trait JoinData[A <: Attributes,
               L <: Entity[A], 
               B <: Keyed
               R <: Document[B],
               O <: Output[A, B]] extends Something[A,L,B,R]{

  def method1(a:A) : String
  def method2(L, R) : O = {
     ...
  } 
  ...
}

When the user implements this, the types L and R do dictate what A and B have to be, however I'm not sure if it's possible to remove A and B from my API.

This problem is resulting in pretty ugly APIs, where it's pretty difficult for a user to understand why they are having to specify some of the types, or even what they should be.

Can anyone point me at some ideas of how I might resolve this (if at all possible!).

1 Answers

It's hard to answer your question without any details about your API and how you use it. Currently it's not even clear why monomorphic

trait JoinData extends Something {
  def method1(a: Attributes): String
  def method2(e: Entity, r: Document): Output = {
     ...
  } 
  ...
}

is insufficient.

You can try to replace (some of) type parameters with type members:

trait Attributes
trait Entity {
  type A <: Attributes
}
trait Keyed
trait Document {
  type B <: Keyed
}
trait Something[L <: Entity, R <: Document]
trait Output[A <: Attributes, B <: Keyed]
trait JoinData[L <: Entity, R <: Document] extends Something[L, R]{
  def method1(a: L#A): String
  def method2(l: L, r: R): Output[L#A, R#B] = ???
}

using type projections or

trait Attributes
trait Entity
trait Keyed
trait Document
trait Something[L <: Entity, R <: Document]
trait Output[A <: Attributes, B <: Keyed]
trait TC[L <: Entity] {
  type A <: Attributes
}
trait TC1[R <: Document] {
  type B <: Keyed
}

abstract class JoinData[L <: Entity, R <: Document](implicit val tc: TC[L]) extends Something[L, R]{
  def method1(a: tc.A) : String
  def method2(l: L, r: R)(implicit tc1: TC1[R]): Output[tc.A, tc1.B] = ???
}

using type classes.

Related