Daniel
Daniel

Reputation: 6039

scala: empty constructor for a class with type tag

Consider the following definition for a class.

case class DiscreteProperty[T <: AnyRef](
  name: String,
  sensor: T => String,
  range: Option[List[String]]
)(implicit val tag: ClassTag[T]) extends TypedProperty[T, String] {

  /// some stuff here 
}

I am getting the following error at some point:

Can't instantiate 'edu.illinois.cs.cogcomp.saul.datamodel.property.features.discrete.DiscreteProperty$$anon$2':

I suppose this is because the class doesn't have an empty constructor. How can I define an empty constructor for this class? I tried the following but it is giving me the following error:

  def this() {
    this("funnyName", T => "" ,Option(List()))
  }

And none of these work:

  def this[T]() {
    this("funnyName", T => "" ,Option(List()))
  }

or

  def this[T]() {
    this[T]("funnyName", T => "" ,Option(List()))
  }

Any ideas how to create an empty constructor for this class with type tag?

Upvotes: 0

Views: 657

Answers (1)

Micheal Hill
Micheal Hill

Reputation: 1649

The issue is that you're not including the implicit parameter in any of your empty constructors. You're treating the primary constructor as having the signature (String, T => String, Option[List[String]]), but that's not quite right. In fact, it's (String, T => String, Option[List[String]])(ClassTag[T]) (note the ClassTag parameter).

Normally this wouldn't be an issue, since the implicit parameter would be retrieved from the scope of that constructor. However, ClassTag is a bit special - it is filled in at compile time with the ClassTag corresponding to whatever your T is. The problem in each of those auxiliary constructors is that the T is still generic, so the compiler doesn't know which ClassTag to include: there's no implicit parameter available within that scope.

So, how can you fix it? The easiest way is probably to include the implicit parameter in any auxiliary constructors:

def this()(implicit tag: ClassTag[T]) = this("funnyName", T => "", Option(List()))

Note that, you don't need to explicitly proved the ClassTag to the chained constructor; it's now part of the scope and will be used implicitly. Of course, you can decide to do so explicitly like so:

def this()(implicit tag: ClassTag[T]) = this("funnyName", T => "", Option(List()))(tag)

Upvotes: 3

Related Questions