30

Coming from a Java background, I'm wondering why List in Scala doesn't have a size field like its Java equivalent LinkedList. After all, with a size field you'll be able to determine the size of the list in constant-time, so why was the size field dropped?

(This question refers to the new collection classes in Scala 2.8 and later. Also, I'm referring to the immutable List, not the mutable one.)

Mechanical snail
  • 29,755
  • 14
  • 88
  • 113
python dude
  • 7,980
  • 11
  • 40
  • 53

6 Answers6

25

One cannot say the size field was dropped, as such list without the size have existed for 50 years since LISP where they are ubiquitous and they are very common in ML and Haskell too, both influential in scala.

The basic reason is that list is a recursive structure. A non empty List is Cons(head: A, tail: List[A]) — except that Cons is in fact called :: to allow a convenient infix notation. You can access the tail (the list without its head element) and that is a list too. And this is done just about all the time. So having the count in the list would not mean adding just one integer, but as many integers as there are elements. This is feasible, but certainly not free.

If you compare with java's LinkedList, LinkedList has a recursive implementation (based on Node, which is more or less like Cons, but with links in both direction). But a LinkedList is not a Node, it owns them (and keep their count). So while it has a recursive implementation, you cannot treat it recursively. It you wanted the tail of a LinkedList as a LinkedList, you would have to either remove the head and have your list changed or else copy all the tail elements to a new LinkedList. So scala's List and java's LinkedList are very different structures.

Didier Dupont
  • 29,398
  • 7
  • 71
  • 90
  • Lists are strict in scala. So every time Cons applied it knows size of the tail and so can increase by 1 and write it to a specific field. Like `Cons(head : A, tail : List[A]) { override val size : Int = tail.size + 1}`. It is possible, but may be considered too space hungry. – ayvango Jul 05 '15 at 14:00
12

Because maintaining this field would

  1. Add memory overhead to all lists;
  2. Add slight time overhead on every list creation.

In Java normally a LinkedList is created, and then manipulated without creating new lists by adding/removing elements; in Scala there are many Lists created.

So it was decided that the overhead isn't worth it.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • 3
    In fact, adding a `size` field would *double* the size of a _cons_ from 8 to 16 bytes, given that objects are allocated in multiples of 8 bytes. – Daniel C. Sobral Nov 19 '11 at 22:55
10

The "disadvantage" of O(n) complexity is not as big as you might think. Martin Odersky mentioned in a talk that (if I remember correctly) 90% of all lists created in all programs in any computer language have a size of 4 or less. (This was in the context of immutability and efficiency)

Therefore, O(n) access time for size is not such a big overhead for most lists created, and, as others have mentioned here, memory savings more than compensates for this.

Adrian
  • 3,762
  • 2
  • 31
  • 40
8

List defines size :

> List(1, 2, 3).size
res4: Int = 3

which has linear o(n) execution time. If you really need a constant time, you should consider the mutable ListBuffer that provides a constant time size implementation.

David
  • 2,399
  • 20
  • 17
  • Which version of Scala is this? Before or after 2.8? – python dude Nov 19 '11 at 22:13
  • at least since 2.8 and later. See : http://www.scala-lang.org/api/2.8.0/scala/collection/immutable/List.html – David Nov 19 '11 at 22:18
  • 2
    Is this constant-time though? it says "equivalent of length" –  Nov 19 '11 at 22:19
  • 2
    In fact your are right. List has linear o(n) size execution time has we can see on the code : https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_0_1/src//library/scala/collection/TraversableOnce.scala#L1 – David Nov 19 '11 at 22:31
  • FWIW immutable `Vector` is an indexed data structure with efficient `length` (among other indexed operations)—so there are alternatives to sacrificing immutability if you have no other good reason to do so. – ches Jun 07 '14 at 11:17
3

Have you checked the length field?

Udo Held
  • 12,314
  • 11
  • 67
  • 93
  • 1
    `length` is a method thst traverses the whole list, hence having `O(n)` complexity. The OP asks why there is no `length` *field* with constant time access. – Tomasz Nurkiewicz Nov 19 '11 at 22:06
  • @Udo Held: Your link is from Scala 2.7.7, which I have no experience with. My question is based on Scala 2.9+, and specifically on the book "Programming in Scala", 2nd Ed., where it's stated in chapter 16 that determining the length of a List is linear in the number of elements. – python dude Nov 19 '11 at 22:09
  • http://www.scala-lang.org/api/current/scala/collection/mutable/LinkedList.html has the length as well and is 2.9. You will find size there as well which is equivalent to length. – Udo Held Nov 19 '11 at 22:15
  • I think the question referred to the immutable List, which is the default one in scala. It has no length field – Didier Dupont Nov 19 '11 at 22:23
0

am I missing something? The size is there:

Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.collection.immutable.List
import scala.collection.immutable.List

scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)

scala> a size
res0: Int = 3
Fred
  • 81
  • 8
  • 3
    exact but it's a o(n) size implementation. The subject was that LinkedList java implementation have a size field that returs the size in constant time. – David Nov 20 '11 at 09:14