hotmeatballsoup
hotmeatballsoup

Reputation: 635

Scala defaulting typed list to be of type String

Scala 2.12 here. I have the following classes:

abstract class AbstractCollector {
  def name() : String
  def collect() : Map[String,AnyVal]
}

class NativeSystemCollector(sysInfo : SystemInfo) extends AbstractCollector {
  override def name(): String = "NativeSystem"

  override def collect(): Map[String, AnyVal] = ???
}

Now I'm trying to write a "provider" method that returns a List[AbstractCollectors]:

def nativeSystemCollector() : NativeSystemCollector = new NativeSystemCollector(systemInfo())

def collectors() : List[AbstractCollector] = {
  var collectors = List[AbstractCollector]()

  collectors += nativeSystemCollector()

  collectors
}

This code gives me a compiler error at collectors += nativeSystemCollector():

"Type mismatch, expected: String, actual: NativeSystemCollector"

Any ideas as to why the compiler thinks collectors is a list of Strings when I clearly declare it as a new list of AbstractCollectors?!?

Upvotes: 0

Views: 42

Answers (2)

James Whiteley
James Whiteley

Reputation: 3464

You should use ListBuffer over List when dealing with mutable lists. For example:

def collectors() : List[AbstractCollector] = {
  var collectorList: ListBuffer[AbstractCollector] = ListBuffer[AbstractCollector]()

  collectorList += nativeSystemCollector()

  collectorList.toList
}

If you really want to use a List, use the :+ symbol:

def collectors() : List[AbstractCollector] = {
  val collectorList: List[AbstractCollector] = List[AbstractCollector]()

  collectorList :+ nativeSystemCollector()
}

Looking at +=, it is constructed like this:

implicit final class any2stringadd[A](private val self: A) extends AnyVal {
  def +(other: String): String = String.valueOf(self) + other
}

Since List[AbstractCollector] doesn't have a += method, I think it assumes you are dealing with Strings and falls over.

Read more here about adding to Lists.

Upvotes: 2

Andrey Tyukin
Andrey Tyukin

Reputation: 44992

It does not think that collectors is a List[String].

Instead, it notices that collectors is immutable and does not have += method. So it tries to desugar

collectors += nativeSystemCollector()

into

collectors = collectors + nativeSystemCollector()

and then doesn't know what the + is supposed to mean. Since there is no + method on List, it implicitly converts collectors into a String, but then notices that nativeSystemCollector() is not another String, and gives up.

If you want to construct a list by appending elements, use a mutable ListBuffer instead:

val collectors = collection.mutable.ListBuffer[AbstractCollector]()

collectors += nativeSystemCollector()

collectors.toList

Appending to a List is expensive anyway.

Upvotes: 3

Related Questions