Why is the ++: operator in the Scala language so strange?
Asked Answered
A

2

4

I am using the ++: operator to get a collection of two collections, but the results I get using these two methods are inconsistent:

scala> var r = Array(1, 2)
r: Array[Int] = Array(1, 2)
scala> r ++:= Array(3)
scala> r
res28: Array[Int] = Array(3, 1, 2)

scala> Array(1, 2) ++: Array(3)
res29: Array[Int] = Array(1, 2, 3)

Why do the ++: and ++:= operators give different results? This kind of difference does not appear with the ++ operator.

The version of Scala I am using is 2.11.8.

Affluent answered 16/11, 2018 at 6:9 Comment(1)
Another interesting effect of ++: and ++:= is that it takes the type of the result collection from the right-hand side (in case they are not both Arrays as here, https://mcmap.net/q/1865606/-what-does-the-operator-do-to-a-list) --- for some definition of "right-hand" in the presence of ++:=.Quintuplet
P
6

Since it ends in a colon, ++: is right-associative. This means that Array(1, 2) ++: Array(3) is equivalent to Array(3).++:(Array(1, 2)). ++: can be thought of as "prepend the elements of the left array to the right array."

Since it's right-associative, r ++:= Array(3) desugars to r = Array(3) ++: r. This makes sense when you consider that the purpose of ++: is prepending. This desugaring holds true for any operator that ends in a colon.

If you want to append, you can use ++ (and ++=).

Proletariat answered 16/11, 2018 at 6:45 Comment(8)
@Quintuplet +:, ::, and ::: come to mind. Again, it's anything that ends in a colon.Proletariat
@Thilo: There is no such thing as an "operator" in Scala. Any method can be called without a period like this: a foo(bar, baz), and when you are passing only one argument, you can leave out the parenthesis like this: a foo bar. That's it. It's just a normal method call, and ++ is just a normal method name like foo. There are two exceptions, though, that mean that Scala actually does have "half-operators". 1) Precedence is determined by the first character of the method name. 2) Methods ending in a : are right-associative when called with operator syntax.Overunder
Note: this also applies to Type Constructors. So, if you have class Foo[A, B] {}, then you can of course say def foo: Foo[Int, String], but you can also say def foo: Int Foo String, and if you have class Foo_:[A, B], then Foo_:[Int, String] is the same as String Foo_: Int.Overunder
@JörgWMittag The bit about type constructors is wild. I know that Scalaz uses it for a pretty "Either" (def foo: String \/ Int). Are there examples of someone doing a right-associative type ?Quintuplet
@Thilo: You don't realize it, but you probably have seen it already, although it's not actually exposed to the user: :: is a method on List, an object, and also a class. But you are normally dealing with List, not with ::.Overunder
Ah, sorry. My bad. :: is unary, not binary. But probably someone is doing that.Overunder
@Quintuplet Shapeless has a binary :: type constructor. Since it is right-associative, Int :: String :: HNil is equivalent to ::[Int, ::[String, HNil]].Proletariat
@JörgWMittag Type constructors can be right-associative (shapeless.:: is an example), but they don't swap the order of their arguments in that case (thankfully).Proletariat
S
0

Here colon(:) means that the function has right associativity

so, for instance coll1 ++: coll2 is similar to (coll2).++:(coll1)

Which generally means the elements of the left collection is prepended to right collection

Case-1:

Array(1,2) ++: Array(3)
Array(3).++:Array(1,2) 
Elements of the left array is prepended to the right array 
so the result would be Array(3,1,2)

Case-2:

 r = Array(1,2)
 r ++:= Array(3) //This could also be written as the line of code below
 r = Array(3) ++: r
   = r. ++: Array(3)
   = Array(1,2). ++: Array(3) //Elements of the left array is prepended to the right array 
 so their result would be Array(1,2,3)

Hope this solves the query Thank you :)

Site answered 16/11, 2018 at 7:44 Comment(1)
++: is a method, not a function.Proletariat

© 2022 - 2024 — McMap. All rights reserved.