Type mismatch when using + operator - scala

I'm currently trying to learn how to use Scala but I'm stuck with some syntax problems.
When I type in the scala prompt:
import scala.collection.immutable._
var q = Queue[Int](1)
println((q+1).toString)
I get the following error:
<console>:12: error: type mismatch;
found : Int(1)
required: String
println((q+1).toString)
I just wanted to use the overloaded + operator of the queue defined as below:
def +[B >: A](elem : B) : Queue[B]
Creates a new queue with element added at the end of the old queue.
Parameters
elem - the element to insert
But it seems that scala does a string concatenation. So, can you help me to understand how to add an element to the queue (without using enqueue which works perfectly; I would like to use the + operator)? And maybe, could you give me some explaination about that behaviour that seems a bit strange for a beginner?
Thank you

You are using the wrong operator (see docs):
scala> var q = Queue[Int](1)
q: scala.collection.immutable.Queue[Int] = Queue(1)
scala> q :+ 2
res1: scala.collection.immutable.Queue[Int] = Queue(1, 2)
scala> 0 +: q
res2: scala.collection.immutable.Queue[Int] = Queue(0, 1)
Since the + operator has no other meaning given those types, Scala defaults to String concatenation, giving you the type mismatch error.

Related

How can I find the definition of methods/operations defined in an implicitly-converted class?

I'm looking at someone else's source code (Scala), where I see the operator :+= being called on a variable of type IndexedSeq. I am looking all over the scaladocs page for that class to figure out what that operator does, but I do not see it. I'm thinking that either it's defined in a class outside of IndexedSeq's inheritance hierarchy, or else the javascript on the scaladocs page is hiding it somewhere I can't see it. (Actually it's neither; see answer below.)
I've hit every button on the scaladocs page trying to unhide everything. I've looked in the web-page's HTML code. There has got to be a way to look up an operator from the documentation of a class to which it can be applied. Hasn't there?
(N.B.: I looked up that operator using symbolhound, so I know what that operator means now. This question is about scala documentation in general, not that particular operator.)
All operators in Scala are normal methods.
You cannot find it because it is compiler magic for re-assignement, it is not an operator. Or to say it another way: it looks like an operator of its own, but it is actually "an operator followed by the = character".
The compiler will magically turn that into a assignment if the operator (here :+) returns the proper type, and the original value was a var, obviously.
Since it is not provided by any implicit nor explicit method on Seq[T] or whatever, it does not appear anywhere in the generated scaladoc.
So to answer the general question:
It is a language construct, so the only place where it is documented is the specification, sadly,
but, if you find some "<?>=" unknown operator somewhere, look for the definition of "<?>", that one is sure to be documented.
Edit: I finally found where this is defined in the SLS:
§6.12.4:
An assignment operator is an operator symbol (syntax category op in (§1.1)) that
ends in an equals character “=”, with the exception of operators for which one of the
following conditions holds:
(1) the operator also starts with an equals character, or
(2) the operator is one of (<=), (>=), (!=).
It also says later on that it only happens when all other options have been tried (including potential implicits).
Is this value assigned to a variable? If it's the case I think this syntax sugar:
scala> var x = IndexedSeq(1,2,3)
x: IndexedSeq[Int] = Vector(1, 2, 3)
scala> x :+= 10
scala> x
res59: IndexedSeq[Int] = Vector(1, 2, 3, 10)
scala> val y = IndexedSeq(1,2,3)
y: IndexedSeq[Int] = Vector(1, 2, 3)
scala> y :+= 10
<console>:16: error: value :+= is not a member of IndexedSeq[Int]
y :+= 10
^
It is syntax sugar for "operation and assignment", like +=:
scala> var x = 10
x: Int = 10
scala> x += 1
scala> x
res63: Int = 11
Which de-sugars to x = x + 1.

Why does "a".::(List()) report error ":: is not member of string"?

See this:
scala> 1 + 1
res0: Int = 2
scala> 1.+(1)
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
res1: Double = 2.0
scala> "a" :: List()
res2: List[String] = List(a)
scala> "a".::(List())
<console>:8: error: value :: is not a member of String
"a".::(List())
^
Why does the error occur?
Try this
List().::("a")
The reason is that :: is a method of List.
From ScalaByExample:
Like any infix operator, :: is also implemented as a method of an
object. In this case, the object is the list that is extended. This is
possible, because operators ending with a ‘:’ character are treated
specially in Scala. All such operators are treated as methods of their
right operand. E.g.,
x :: y = y.::(x) whereas x + y = x.+(y)
Note, however, that operands of a binary operation are in each case
evaluated from left to right. So, if D and E are expressions with
possible side-effects,
D :: E
is translated to
{val x = D; E.::(x)}
in order to maintain the left-to-right order of operand evaluation.
In scala methods which ends with : got applied in reverse order.
So when you write a::list it is actually list.::(a). String doesn't have :: method, so the solution is to write List().::("a") or Nil.::("a")
Because of operator precedence. In Scala methods which ends with : are right associative. So you should call List().::("a")
If you want to use left associative method then you should write List("a") ++ List(), but that's not always a good choice, cause it has linear execution time

Type mismatch with map and flatMap

While trying to play with Options in scala I have come across this peculiar problem.
I started off with creating a List[Option[Int]] as follows:
scala> List(Some(1),Some(2),None,Some(3))
res0: List[Option[Int]] = List(Some(1), Some(2), None, Some(3))
Then I tried to map an addition to 1 over the entries of the list in res0 as follows:
scala> res0 map (_ + 1)
This gave me the error:
<console>:9: error: type mismatch;
found : Int(1)
required: String
res0 map (_ + 1)
^
Then I tried flatMapping an addition over the entries as follows:
scala> res0 flatMap (_ + 1)
This gave me the same error:
<console>:9: error: type mismatch;
found : Int(1)
required: String
res0 flatMap (_ + 1)
^
But something like res0.flatMap(r => r) works just fine with a result of:
res9: List[Int] = List(1, 2, 3)
Can anybody tell me why adding the entry to 1 would fail for both map and flatMap?
The first two things you tried failed because you are trying to add an Option to an Int, and that's not possible.
The weird error message happens because Scala assumes, since Option doesn't have a + method, that you are trying String concatenation, but you'd have to either add an Option to a String, or a String to an Option, and you are doing neither, hence the error message.
In the last case, you are not trying to add anything, you are simply returning Option as is, hence no error message.
To increment all values that are not None, you need to map also each Option element of the list, like so:
scala> res0.map(_.map(_ + 1))
res1: List[Option[Int]] = List(Some(2), Some(3), None, Some(4))
If you want to filter out the Nones, you would indeed use a flatMap:
scala> res0.flatMap(_.map(_ + 1))
res2: List[Int] = List(2, 3, 4)
Both the function given to flatMap as well as the function given to map take a value of the list's element type - in this case Option[Int]. But your function _ + 1 expects an Int, not an Option[Int], so you can't use it as the argument to either map or flatMap in this case. Further the function given to flatMap should return an iterable¹, but your function would return a number.
This will do what you want: res0 flatMap (_ map (_ + 1)). Here the function given to flatMap takes an Option[Int] and returns an Option[Int] by calling map on the option. flatMap then takes the options returned by the function and concatenates them.
¹ Technically a GenTraversableOnce.
You try to invokee.+(1) on every element e in a List[Option[Int]], but + is not a function declared by Option[_]. String concatenation, however, would be possible (I assume there is an implicit from Any to String), but only if the second argument were a string as well (not sure why the implicit whose existence I assumed isn't considered here).
You can overcome this problem by doing working with a default value as suggested by #korefn, or "hide" the differentiation between Some(x) and None in another invocation of map, namely by
map(_.map(_ + 1))
They are failing because the types are wrong and the compiler correctly states it as such.
The map case fails because map expects a function A => B. In your code, A => B is really Int => Int which will not work because calling map on your list means that A is actually Option[Int].
Furthermore, flatMap expects a function of the form A => F[B]. So you will get your answer if you did res0 flatMap { o => o map { a => a + 1 } }. This basically is the expansion of:
for {
element <- res0 // o above
value <- element // a above
} yield value + 1
Try to use get to extract the value from Some[Int] to Int allowing for calculation value + 1 ie:
res0 map{_.getOrElse(0) + 1}
As pointed out by #Sepp2k you could alternatively use a collect to avoid having a default for None
res0 collect {case Some(x) => x + 1 }

Scala: oddness adding to a Map

I have just noticed that whilst I need clarifying parens when adding a pair to a map, I don't need them when doing a re-assignment:
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.
Get me some values
scala> var n = Map.empty[Int, String]
n: scala.collection.immutable.Map[Int,String] = Map()
Trying to add to the map with no clarifying parentheses:
scala> n + 1 -> ""
<console>:30: error: type mismatch;
found : Int(1)
required: (Int, ?)
n + 1 -> ""
^
Fails as I expected it to. But doing the same via a re-assignment does not:
scala> n += 1 -> ""
scala> n
res12: scala.collection.immutable.Map[Int,String] = Map(1 -> "")
What is going on? Why is this not failing? Is scalac adding parens itself?
It's just a precedence issue. + and - have the same precedence. = is lower. So Scala sees (n + 1) -> "" in the former case, and n += (1 -> "") in the latter (which is then transformed to n = (n + (1 -> "")) according to the normal rules for assignment operators.
According to scala reference (6.12.4):
Assignment operators are treated specially in that they can be expanded to assignments if no other interpretation is valid. ... The
re-interpretation occurs if the following two conditions are fulfilled.
1. The left-hand-side l does not have a member named +=, and also cannot be converted by an implicit conversion (§6.26) to a value with a member named > +=.
2. The assignment l = l + r is type-correct. In particular this implies that l refers to a variable or object that can be assigned to, and that is convertible to a value with a member named +.
(1) Immutable Map has no member named += (mutable has) and AFAIK, has no implicit conversions to something with that and assignment is definitely type correct (2): n defined as a variable and has member +.

What does param: _* mean in Scala?

Being new to Scala (2.9.1), I have a List[Event] and would like to copy it into a Queue[Event], but the following Syntax yields a Queue[List[Event]] instead:
val eventQueue = Queue(events)
For some reason, the following works:
val eventQueue = Queue(events : _*)
But I would like to understand what it does, and why it works? I already looked at the signature of the Queue.apply function:
def apply[A](elems: A*)
And I understand why the first attempt doesn't work, but what's the meaning of the second one? What is :, and _* in this case, and why doesn't the apply function just take an Iterable[A] ?
a: A is type ascription; see What is the purpose of type ascriptions in Scala?
: _* is a special instance of type ascription which tells the compiler to treat a single argument of a sequence type as a variable argument sequence, i.e. varargs.
It is completely valid to create a Queue using Queue.apply that has a single element which is a sequence or iterable, so this is exactly what happens when you give a single Iterable[A].
This is a special notation that tells the compiler to pass each element as its own argument, rather than all of it as a single argument. See here.
It is a type annotation that indicates a sequence argument and is mentioned as an "exception" to the general rule in section 4.6.2 of the language spec, "Repeated Parameters".
It is useful when a function takes a variable number of arguments, e.g. a function such as def sum(args: Int*), which can be invoked as sum(1), sum(1,2) etc. If you have a list such as xs = List(1,2,3), you can't pass xs itself, because it is a List rather than an Int, but you can pass its elements using sum(xs: _*).
For Python folks:
Scala's _* operator is more or less the equivalent of Python's *-operator.
Example
Converting the scala example from the link provided by Luigi Plinge:
def echo(args: String*) =
for (arg <- args) println(arg)
val arr = Array("What's", "up", "doc?")
echo(arr: _*)
to Python would look like:
def echo(*args):
for arg in args:
print "%s" % arg
arr = ["What's", "up", "doc?"]
echo(*arr)
and both give the following output:
What's
up
doc?
The Difference: unpacking positional parameters
While Python's *-operator can also deal with unpacking of positional parameters/parameters for fixed-arity functions:
def multiply (x, y):
return x * y
operands = (2, 4)
multiply(*operands)
8
Doing the same with Scala:
def multiply(x:Int, y:Int) = {
x * y;
}
val operands = (2, 4)
multiply (operands : _*)
will fail:
not enough arguments for method multiply: (x: Int, y: Int)Int.
Unspecified value parameter y.
But it is possible to achieve the same with scala:
def multiply(x:Int, y:Int) = {
x*y;
}
val operands = (2, 4)
multiply _ tupled operands
According to Lorrin Nelson this is how it works:
The first part, f _, is the syntax for a partially applied function in which none of the arguments have been specified. This works as a mechanism to get a hold of the function object. tupled returns a new function which of arity-1 that takes a single arity-n tuple.
Futher reading:
stackoverflow.com - scala tuple unpacking