scravy
scravy

Reputation: 12283

Generic parameters for a constructor in Scala

Consider the following contrived Java example:

public class Example {

    private final Object value;
    private final List<?> aListOfTheseThings;

    public <T> Example(final T t, final List<T> aListOfTheseThings) {
        this.value = t;
        this.aListOfTheseThings = aListOfTheseThings;
    }

}

What I care about in this Example:

  1. Example is not parameterized
  2. The constructor is paremeterized and makes sure that whatever you pass in, the list is parameterized in the same type of t

(This is a contrived example, I do not really care about (2) but I really do care about having a type parameter there which is not mentioned in the definition of the class).

Now in Scala I tried the following:

class Example private[this](
  private val value: AnyRef,
  private val aListOfTheseThings: List[_]) {

  def this[T](t: T, aListOfTheseThings: List[T]) {
    this(t, aListOfTheseThings)
  }
}

...but this is not possible. Apparently a type parameter is not valid in a constructor (in this).

Any chance of translating the above Java code into Scala?

Upvotes: 4

Views: 2331

Answers (2)

Owen
Owen

Reputation: 39366

Nyavro's suggestion of a helper apply method is a good one. Another option that might be appropriate in some cases is subclassing:

trait Example {
  val value: Any
  val things: List[_]
}

class SameTypeExample[T](val value: T, val things: List[T]) extends Example

The advantage of subclassing is that the constraint that value and things store the same type is not lost, and can be re-discovered by pattern matching:

def handle(example: Example) = example match {
  case st: SameTypeExample[t] =>
    st.value :: st.things    
}   

Subclassing is a general technique in Scala for temporarily hiding information that was present at construction time.

Upvotes: 7

Nyavro
Nyavro

Reputation: 8866

Maybe this help:

sealed trait Example

object Example {
  def apply[T <: AnyRef](t:T, aListOfTheseThings: List[T]): Example = 
    new ExampleImpl(t, aListOfTheseThings)

  private class ExampleImpl(
    val value: AnyRef, 
    val aListOfTheseThings: List[_]) extends Example 
}

This makes private constructor of class Example. value and aListOfTheseThings are not accessed via Example trait (unless you make it accessible)

Upvotes: 8

Related Questions