Why variations in operators?

Long time lurker, first time poster.

In Scala, I look for advantages as to why it was preferable to vary the operators depending on the type. For example why it was:

Vector(1, 2, 3) :+ 4

      

defined as an advantage over:

Vector(1, 2, 3) + 4

      


Or:

4 +: Vector(1,2,3)

      

over

Vector(4) + Vector(1,2,3)

      


Or:

Vector(1,2,3) ++ Vector(4,5,6)

      

over

Vector(1,2,3) + Vector(4,5,6)

      


So here we have: +, + :, and ++ when + one might be enough. I am new to Scala and I succumb. But this seems unnecessary and confusing for a language that tries to be clean with its syntax.

I did several google and stack overflow searches and only found questions about specific operators and operator overloading in general. But there was no reason to believe that it was necessary to divide +, for example, into several options.

FWIW, I could overload operators using implicit classes like below, but I suppose this will only cause confusion (and tisk tisks) for experienced Scala programmers using / reading my code.

object AddVectorDemo {

    implicit class AddVector(vector : Vector[Any]) {
        def +(that : Vector[Any]) = vector ++ that
        def +(that : Any) = vector :+ that
    }

    def main(args : Array[String]) : Unit = {
        val u = Vector(1,2,3)
        val v = Vector(4,5,6)
        println(u + v)
        println(u + v + 7)
    }
}

      

Outputs:

Vector (1, 2, 3, 4, 5, 6)
Vector (1, 2, 3, 4, 5, 6, 7)

+3


source to share


2 answers


This is a fair question, and I think it has a lot to do with legacy code and Java compatibility. Scala copied Java +

for string concatenation, which has tricky stuff.

This +

allows us to do:

(new Object) + "foobar" //"java.lang.Object@5bb90b89foobar"

      

So what would we expect if +

for List

, and we did List(1) + "foobar"

? One might expect List(1, "foobar")

(like List[Any]

) as we get if we use :+

, but the String-concatenation overload caused by Java would complicate this because the compiler was unable to resolve the overload.



Odinsky even once commented:

There should never be a + method on collections that are covariant in the type of their elements. Sets and maps are not variants, so they can have a + method. It's all pretty delicate and messy. We'd be better off if we didn't try to duplicate Java + for string concatenation. But when developing Scala, the idea was to keep essentially all Java expression syntax, including String +. And it's too late to change that now.

There are several discussions (albeit in a different context) of answers to this similar question .

+5


source


It takes a surprisingly long traversal through variance to answer. I will try to keep it as short as possible.

First, note that you can add anything to an existing Vector:

scala> Vector(1)
res0: scala.collection.immutable.Vector[Int] = Vector(1)

scala> res0 :+ "fish"
res1: scala.collection.immutable.Vector[Any] = Vector(1, fish)

      

Why are you doing this? Well, if B extends A

we also want to be able to use Vector[B]

where called Vector[A]

, we need to allow Vector[B]

the same types of things to be added that can add Vector[A]

. But everything is expanding Any

, so we need to add something that can add Vector[Any]

that everything is there.

Creating Vector

most other non-Set collections is a design decision, but that's what most people expect.

Now try adding a vector to a vector.



scala> res0 :+ Vector("fish")
res2: scala.collection.immutable.Vector[Any] = Vector(1, Vector(fish))

scala> res0 ++ Vector("fish")
res3: scala.collection.immutable.Vector[Any] = Vector(1, fish)

      

If we only had one operation, +

we would not be able to indicate which of these things we had in mind. And we really could do it. They are both perfectly reasonable things to try. We could try to guess from the types, but in practice it’s better to just ask the programmer to tell you directly what they mean. And since there are two different things, there are two ways to ask.

Does this happen in practice? With collections of collections, yes, all the time. For example using +

:

scala> Vector(Vector(1), Vector(2))
res4: Vector[Vector[Int]] = Vector(Vector(1), Vector(2))

scala> res4 + Vector(3)
res5: Vector[Any] = Vector(Vector(1), Vector(2), 3)

      

Perhaps this is not what I wanted.

+6


source







All Articles