2

Working with collections in Scala, it's common to need to use the empty instance of the collection for a base case. Because the default empty instances extend the collection type class with a type parameter of Nothing, it sometimes defeats type inference to use them directly. For example:

scala> List(1, 2, 3).foldLeft(Nil)((x, y) => x :+ y.toString())
<console>:8: error: type mismatch;
 found   : List[String]
 required: scala.collection.immutable.Nil.type
              List(1, 2, 3).foldLeft(Nil)((x, y) => x :+ y.toString())

                                                  ^

fails, but the following two corrections succeed:

scala> List(1, 2, 3).foldLeft(Nil: List[String])((x, y) => x :+ y.toString())
res9: List[String] = List(1, 2, 3)

scala> List(1, 2, 3).foldLeft(List.empty[String])((x, y) => x :+ y.toString())
res10: List[String] = List(1, 2, 3)

Another place I've run into a similar dilemma is in defining default parameters. These are the only examples I could think of off the top of my head, but I know I've seen others. Is one method of providing the correct type hinting preferable to the other in general? Are there places where each would be advantageous?

acjay
  • 34,571
  • 6
  • 57
  • 100
  • See also: http://stackoverflow.com/questions/24793871/can-you-specify-type-argument-for-none-or-tell-compiler-that-its-an-optionstri/24797748?noredirect=1#comment38502539_24797748. I posted this variation by request. – acjay Jul 17 '14 at 14:46
  • 3
    i think it's semantically better to use _empty_ instances when you need (obviously) empty collection. values like Nil is better used in pattern matching and type parameters – wedens Jul 17 '14 at 15:11
  • 1
    Another option in your scenario is: `List(1, 2, 3).foldLeft[List[String]](Nil)((x, y) => x :+ y.toString())`. I think it depends on your style. I would agree with @wedens and go with `empty` in such situations. – Kigyo Jul 17 '14 at 15:51
  • Be aware the `Nil` by itself has type `List[Nothing]` which makes its use in some circumstances type-incompatible. This is the case in your first snippet where the compiler cannot infer types from arg lists further right to those further left, only from left to right. – Randall Schulz Jul 17 '14 at 15:52
  • I get this a lot when Intellij suggests replacing `xs.map().getOrElse(Seq.empty)` with `.foldLeft`. I just checked, and sure enough `System.identityHashCode(List.empty[String]) == System.identityHashCode(Nil)`. – Richard Close Jul 17 '14 at 16:27

1 Answers1

1

I tend to use Nil (or None) in combination with telling the type parameterized method the type (like Kigyo) for the specific use case given. Though I think using explicit type annotation is equally OK for the use case given. But I think there are use cases where you want to stick to using .empty, for example, if you try to call a method on Nil: List[String] you first have to wrap it in braces, so that's 2 extra characters!!.

Now the other argument for using .empty is consistency with the entire collections hierarchy. For example you can't do Nil: Set[String] and you can't do Nil: Option[String] but you can do Set.empty[String] and Option.empty[String]. So unless your really sure your code will never be refactored into some other collection then you should use .empty as it will require less faff to refactor. Furthermore it's just generally nice to be consistent right? :)

To be fair I often use Nil and None as I'm often quite sure I'd never want to use a Set or something else, in fact I'd say it's better to use Nil when your really sure your only going to deal with lists because it tells the reader of the code "I'm really really dealing with lists here".

Finally, you can do some cool stuff with .empty and duck typing check this simple example:

def printEmptyThing[K[_], T <: {def empty[A] : K[A]}](c: T): Unit = 
  println("thing = " + c.empty[String])

printEmptyThing[List, List.type](List)
printEmptyThing[Option, Option.type](Option)
printEmptyThing[Set, Set.type](Set)

will print:

> thing = List()

> thing = None

> thing = Set()
samthebest
  • 30,803
  • 25
  • 102
  • 142