You know that scene in Goodbye and Thanks For All The Fish where Arthur is so deliriously happy he stops a waiter and demands to know, "Why is this food so good?" I'm in that situation. Scala seems to be doing exactly what I'd want, but I don't understand how it's doing it. Consider the following:
scala> var v = Nil:List[String];
v: List[String] = List()
scala> v.length
res38: Int = 0
scala> v ::= "Hello"
scala> v.length
res39: Int = 1
scala> Nil.length
res40: Int = 0
Which is exactly what you'd hope for, but how is it happening?
Nil is an object that extends List[Nothing], which is a subtype of List[String], so assignment works fine, but it's an immutable list, isn't it? So I shouldn't be able to append to it. But I can append to it, or at least I can append to v, which I thought point to Nil. v is changed, but Nil isn't.
So, WTF? Does Scala have some clever copy-on-modify semantics I'm unaware of? Is Nil really a function that returns empty lists? More broadly, is there some way I could have made the REPL answer these questions?
When Scala sees
v ::= "Hello"
it first checks if v
knows the method ::=
. In this case (type List
), it doesn't, so, because the method consists only of symbols and ends with an =
sign, it tries something else:
v = v.::("Hello")
which, incidentally, is written "Hello" :: v
in infix notation. Now, since v
knows the method ::
, that works and returns a new List
, which is then assigned to v
as indicated.
By the way, it is prepending, not appending.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With