Adding an item to scala.collection.mutable.HashMap - scala

I tried to add an element to a Scala HashMap
val c2 = new collection.mutable.HashMap[String,Int]()
c2 += ("hh",1)
but the above gives me a compile error.
[error] found : String("hh")
[error] required: (String, Int)
[error] c2 += ("hh", 1)
[error] ^
[error] /scalathing/Main.scala:5: type mismatch;
[error] found : Int(1)
[error] required: (String, Int)
[error] c2 += ("hh", 1)
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 3 s, completed Sep 1, 2016 1:22:52 AM
The pair I'm adding seems to be of the correct type as demanded by the HashMap. Why do I get a compile error?

The += operator is overloaded to work with variadic arguments. Therefore when the compiler sees c2 += ("hh", 1) it interprets that as two arguments being passed in, one of which is "hh" and the other of which is 1. You can fix that either by using the -> operator, i.e. c2 += ("hh" -> 1) or enclosing the tuple in another series of parantheses, i.e. c2 += (("hh, 1)).
Slightly gory details below as requested in the comments.
As for how all this works, in the case of mutable collections such as HashMap, += is simply an ordinary method called with operator syntax (i.e. spaces instead of a .) or "infix notation" as the Scala community calls it, as any method in Scala can be. It is provided by the Growable trait which mutable collections mix in. You can see on the documentation for Growable both the single argument += method and the variadic method. In other words the following code would have also worked.
c2.+=(("hh", 1))
Not all +=s are created equal however. += commonly shows up in vars as well. Although it can be called with method syntax ., it's magic syntax sugar implemented directly by the Scala compiler. In particular any nonalphanumeric name followed by an = gets desugared. x $NAME= y becomes x = x.$NAME(y). In this case $NAME= is variadic if and only if $NAME is variadic.
var i = 0
i += 1
i.+=(1) // Also compiles
case class SuperInt(raw: Int) {
def &*&(x: SuperInt) = SuperInt(raw + x.raw)
}
var x = SuperInt(1)
x &*&= SuperInt(1) // This works
x.&*&=(SuperInt(1)) // As does this
x &*&= (SuperInt(1), SuperInt(1)) // Does not compile because &*& is not variadic

Related

Scala - Cannot resolve symbol - Looping through map

I am doing programming in scala for looping through map.
Below is my code which works fine.
val names = Map("fname" -> "Robert", "lname" -> "Goren")
for((k,v) <- names ) println(s"Key: $k, Value : $v")
When looping through the map, if I give (K,V) instead of (k,v), the program is not compiling. It gives cannot resolve symbol error.
Below is my for loop -
for((K,V) <- names ) println(s"Key: $K, Value : $V")
I am executing this program in IntelliJ IDEA 15 scala worksheet.
Can anyone please explain the reason for this error.
It doesn't compile for the same reason this code doesn't compile:
val (A,B) = (1,2)
// error: not found: value A
// error: not found: value B
but this does compile:
val (a,b) = (1,2)
// a: Int = 1
// b: Int = 2
Constant names should be in upper camel case. That is, if the member
is final, immutable and it belongs to a package object or an object,
it may be considered a constant
Method, Value and variable names should be in lower camel case
Source: http://docs.scala-lang.org/style/naming-conventions.html

Chisel Programming Error

I am having a problem in my Chisel code, I tried the following approach
deqReg := Cat((0 until ports).map(ownReg === Cat(io.configVal(portBits*(_) + 2),io.configVal(portBits*(_)+ 1), io.configVal(portBits*(_)))))
but I am getting the following error when running the above code
[error] /home/jayant/Dropbox/FIFO/fifo.scala:24: missing parameter type for expanded function ((x$1) => portBits.$times(x$1).$plus(2))
[error] deqReg := Cat((0 until ports).map(ownReg === Cat(io.configVal(portBits*(_) + 2),io.configVal(portBits*(_)+ 1), io.configVal(portBits*(_)))))
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 2 s, completed 4 Sep, 2015 12:31:40 PM
can any one tell what is this error and how to correct it.
You have multiple nested functions in your map which would make it impossible for the Scala compiler to infer the type of the argument. In other words you cannot user the "_" placeholder here. The placeholder just replaces the argument of the innermost function within the expression. Try a fully specified anonymous function (or a partial function) like this:
deqReg := Cat((0 until ports).map{ case i:Int => ownReg === Cat(io.configVal(portBits*i + 2), io.configVal(portBits*i + 1), io.configVal(portBits*i))})
Scala is a quite powerful language and you'd most probably be able to find a more elegant way to write that code.

+= on a Vector gives strange / wrong type errors

I have a variable v that is a Vector, and I'm trying to add an element to it using +=. It complains that it expects a String instead of an Int:
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> var v = Vector[Int]()
v: scala.collection.immutable.Vector[Int] = Vector()
scala> v += 3
<console>:9: error: type mismatch;
found : Int(3)
required: String
v += 3
^
Why does it expect a String? When I give it a String (which is ofcourse wrong), it says it expects a Vector[Int]:
scala> v += "three"
<console>:9: error: type mismatch;
found : String
required: scala.collection.immutable.Vector[Int]
v += "three"
^
And when I give it a Vector[Int], it again expects a String:
scala> v += Vector(3)
<console>:9: error: type mismatch;
found : scala.collection.immutable.Vector[Int]
required: String
v += Vector(3)
^
Why does this happen?
I know I can add an element using +:=. But why can I not use +=, like for a Set?
Let's go through this cases one by one:
scala> v += 3
<console>:9: error: type mismatch;
found : Int(3)
required: String
v += 3
^
Here is the main problem that Vector have no + method, so compiler will default to string concatination (which is highly criticized recently as a design flaw, by the way). The problem is that left side (vector) is convertible automatically to string (via Vector.toString), but right one is not.
scala> v += "three"
<console>:9: error: type mismatch;
found : String
required: scala.collection.immutable.Vector[Int]
v += "three"
^
Here concatenation is ok, but you're trying to put result of type String to variable of type Vector[Int], which is why compiler complains. But if you define v as Any compiler will stop complaining:
var v: Any = Vector[Int]()
v += "foo"
// res1: Any = Vector()foo
Now, next case
scala> v += Vector(3)
<console>:9: error: type mismatch;
found : scala.collection.immutable.Vector[Int]
required: String
v += Vector(3)
^
String concatenation again, and again, result of type String goes to the variable of type Vector.
Now, talking about why Vector does not have the very same + operation: ordinary Set have no notion of order, whereas Vector, and Seq in general have and + would be confusing: do I add to the end or to the start? So instead of implicit rule, you have to explicitly decide whether you use :+ or +:.

Scala Compilation Error using Partition

scala> val set = Set("apricot", "banana", "clementine", "durian", "fig", "guava", "jackfruit", "kiwi", "lime", "mango")
set: scala.collection.immutable.Set[java.lang.String] = Set(banana, durian, fig, jackfruit, lime, mango, clementine, apricot, kiwi, guava)
scala> set.partition(_ length > 5)
<console>:1: error: ')' expected but integer literal found.
set.partition(_ length > 5)
^
scala> set.partition(_.length > 5)
res5: (scala.collection.immutable.Set[java.lang.String], scala.collection.immutable.Set[java.lang.String]) = (Set(banana, durian, jackfruit, clementine, apricot),Set(fig, lime, mango, kiwi, guava))
Can someone please explain why does it complain when I execute
set.partition(_ length > 5)
and not when I execute
set.partition(_.length > 5)
I have also tried the following with little success:
scala> set.partition((_ length) > 5)
<console>:9: error: missing parameter type for expanded function ((x$1) => x$1.length)
set.partition((_ length) > 5)
^
When you drop the dot, Scala assumes you have a one-parameter method. In other words, when you say _ length > 5 it thinks that length is a method requiring one argument, that > is that argument, and then it doesn't konw what to do with the 5.
Notice that this is similar to when you write 5 + 5. This statement is the same as writing 5.+(5), but you are dropping the dot and parentheses. Scala notices the missing dot and assumes (correctly) that + is a method requiring a single argument.
If you write "abc" length by itself, then there is nothing for Scala to assume is the argument, so it then realizes that length doesn't require one.
So:
"abc".length // fine
"abc" length // fine
"abc".length > 4 // fine
("abc" length) > 4 // fine
"abc" length > 4 // error!
Thus, you need either a dot or parentheses to tell the compiler that "abc" and length go together and have no additional argument.
In terms of coding style, I suggest you always use the dot for zero-arg methods. I find it more readable and it will help you to avoid compilation errors such as this one.
When you write:
set.partition(_ length > 5)
// ^ object
// ^ method
// ^ parameter
it treats length as a method that receives one parameter, >.
While when you write:
set.partition(_.length > 5)
// ^------^ object
// ^ method
// ^ parameter
it treats _.length as the object, > is the parameter, and 5 is the argument.

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 +.