0

I am trying to learn scala. I was looking at the documentation for queues (https://www.scala-lang.org/api/current/scala/collection/immutable/Queue.html).

It is my understanding that methods that end in a colon are right associative. However, to me, the ++: does not apear to do so:

import scala.collection.immutable.Queue
val q0 = Queue(0)
val q1 = Queue(1)
q0 ++ q1 // yields Queue(0,1) as I expected
q0 ++: q1 // yields Queue(0,1) as well;  I expected Queue(1,0)

Both the documentation and experimentation seem to indicate that ++: is not right associative. The documentation for both ++ and ++: say left followed by the right and that is what happens above, I just don't understand why. Clearly, there is something I am missing. Could someone please clarify this for me?

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
William Allcock
  • 134
  • 2
  • 9
  • 1
    Why would you expect different results? The documentation of the method clearly states that it gives the same result as `++:`. I'm too lazy to look it up, but I am assuming it is simply implemented as `def ++:(other) = other ++ this`. – Jörg W Mittag Mar 10 '19 at 08:51

1 Answers1

4

A very simple experiment:

case class A(s: String) { def ++:(a: A) = A(s"(${a.s} + ${s})") }
A("x") ++: A("y") ++: A("z")

gives:

A((x + (y + z)))

so it's x + (y + z) and not (x + y) + z. Thus, the ++: is right-associative, as advertised.

Note that it's ${a.s} + ${s} and not ${s} + ${a.s}. In the case of Queue, it's probably analogous, something like:

def ++:(left: Queue[A]): Queue[A] = left ++ this

so the order of elements appears "as it should be" when you write q0 ++: q1 which desugars into q1.++:(q0) and then expands into q0 ++ q1.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • Thank you. The last sentence is what clarified this for me. I find it... interesting that it is right associative to q1 to start, but when you rewrite it in dot notation it becomes right associative to q0. Since ++ and ++: appear to give identical results, when would you use one vs the other? – William Allcock Mar 10 '19 at 17:47
  • @WilliamAllcock The [code](https://github.com/scala/scala/blob/v2.12.8/src/library/scala/collection/TraversableLike.scala#L186) seems to be almost the same for `++` and `++:`, only the roles of `this` and `that` are flipped. So, the difference seems to be purely cosmetic. Maybe you might want to use `++:` when you want to emphasize that the queue on the right is something "big and stable", and the queue on the left is some "small increment". To be honest, I don't remember that I've ever used `++:` for anything. – Andrey Tyukin Mar 10 '19 at 18:43
  • Very confusing. The 2.13 docs say `++` is an alias for `concat` and `++:` is an alias for `prependedAll`. A quick inspection shows that prepending is expensive. It doesn't say that `concat` is an alias for `appendedAll`. The quick way to check parsing is `q0 ++: q1 //print` in REPL. – som-snytt Mar 10 '19 at 23:14
  • @AndreyTyukin I found this in the comments of the code link you gave above: * It differs from `++` in that the right operand determines the type of * the resulting collection rather than the left one. * Mnemonic: the COLon is on the side of the new COLlection type. – William Allcock Mar 15 '19 at 13:32
  • @WilliamAllcock Wellyeah... So, in the end of the day, what does it tell us? *"The type of the value returned by the method is determined by the return type of the method"*? True... Difficult to argue with that one. The mnemonic seems strange. Looks like something the author of the method came up with and then forgot ten minutes later. – Andrey Tyukin Mar 15 '19 at 13:37