Reputation: 4902
Please check this
import scala.collection.mutable.LinkedList
var l = new LinkedList[String]
l append LinkedList("abc", "asd")
println(l)
// prints
// LinkedList()
but
import scala.collection.mutable.LinkedList
var l = new LinkedList[String]
l = LinkedList("x")
l append LinkedList("abc", "asd")
println(l)
// prints
// LinkedList(x, abc, asd)
Why does the second code snippet works but the first one doesnt? This is on Scala 2.10
Upvotes: 20
Views: 21653
Reputation: 13342
As I understand it is related to First/Last (Nil
) element in the list (if list is empty Nil
is first and last element at the same time).
LinkedList (still) follows "primitive charm" strategy. So it does not try to add/append new data to/after Nil
, to have possible result like this: {Nil, newElement}. (After all Nil
should be last element)
Of course it could check if
list is empty then put addingList
to the beginning and Nil
to the end. But this would be "too smart", I guess.
But, anyway append()
returns "expecting" result Like this:
val addingList = new LinkedList[String]("a", "b")
val result = emptyList append addingList
result = {"a", "b"}.
In this case it returns 'addingList' itself, and/but does not change initial list.
If we try to assign newElement to the next
ref:
emptyList.next = LinkedList("whatever")
As result we would have emtyList changed like this:
LinkedList(null, whatever)
I.e. it creates fist element as null, since we have used next()
assigning new/next element to it. So it moves Nil to the end, because first element which is null, has next reference to new element we added (addingElelement
).
Because
"the "emptyList" is also the "head" link"
and head in our case head is Nil
, but Nill
can not have next, so it has to create new first element (which is has null value) with next() referece to our new addingElelement
.
Personally I find it "too much primitive" and not "so much elegant". But it depends, I guess.
Task oriented story:
For my initial task (why I start thinking about this 'strange' list behaviour [even though it's mutable]) -- I wanted to use mutable list for a class/object called Dictionary
which would keep Words
in it (dictionary by default has not any words). And I would have methods like addWord(wod:String)
for adding new words. For now my implementation will be changed (I'm not going to use this LinkedList
, but rather MutableList
. It seems it is more mutable than previous one):
object Dictionary {
val words = new mutable.MutableList[Word]();
def addWord(word: Word): Unit = {
words += word;
}
}
But possible implementation could be like this:
object Dictionary {
var words = new mutable.LinkedList[Word]();
def addWord(word: Word): Unit = {
if (words.isEmpty) {
words = words append( mutable.LinkedList[Word](word) ) // rely on append result
} else {
words append( mutable.LinkedList[Word](word) )
}
}
}
But then I have to use var
instead of val
, and I should transform every new Word to LinkedList
, and my logic became more complicated.
Upvotes: 4
Reputation: 24413
The documentation says If this is empty then it does nothing and returns that. Otherwise, appends that to this.
. That is exactly, what you observed. If you really need a mutable list, I would suggest you to use scala.collection.mutable.ListBuffer
instead, with it you can do
val lb = new ListBuffer[Int]
scala> lb += 1
res14: lb.type = ListBuffer(1)
scala> lb
res15: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1)
scala> lb ++= Seq(1,2,3)
res17: lb.type = ListBuffer(1, 1, 2, 3, 1, 2, 3)
scala> lb
res18: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 1, 2, 3, 1, 2, 3)
Upvotes: 25