Reputation: 36521
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?
Upvotes: 2
Views: 327
Reputation: 31513
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()
Upvotes: 1