What is the most concise way to increment a variable of type Short in Scala? - scala

I've been working a bit lately on implementing a binary network protocol in Scala. Many of the fields in the packets map naturally to Scala Shorts. I would like to concisely increment a Short variable (not a value). Ideally, I would like something like s += 1 (which works for Ints).
scala> var s = 0:Short
s: Short = 0
scala> s += 1
<console>:9: error: type mismatch;
found : Int
required: Short
s += 1
^
scala> s = s + 1
<console>:8: error: type mismatch;
found : Int
required: Short
s = s + 1
^
scala> s = (s + 1).toShort
s: Short = 1
scala> s = (s + 1.toShort)
<console>:8: error: type mismatch;
found : Int
required: Short
s = (s + 1.toShort)
^
scala> s = (s + 1.toShort).toShort
s: Short = 2
The += operator is not defined on Short, so there appears to be an implicit converting s to an Int preceding the addition. Furthermore Short's + operator returns an Int.
Here's how it works for Ints:
scala> var i = 0
i: Int = 0
scala> i += 1
scala> i
res2: Int = 1
For now I'll go with s = (s + 1).toShort
Any ideas?

You could define an implicit method that will convert the Int to a Short:
scala> var s: Short = 0
s: Short = 0
scala> implicit def toShort(x: Int): Short = x.toShort
toShort: (x: Int)Short
scala> s = s + 1
s: Short = 1
The compiler will use it to make the types match. Note though that implicits also have a shortfall, somewhere you could have a conversion happening without even knowing why, just because the method was imported in the scope, code readability suffers too.

Related

Scala: type mismatch

I spend awful amount of time to figure it out following:
rmseList is a List of doubles
val rmseList = List(Double)
var tempRMSE : Double = 0.0;
for(rmse <- rmseList) {
val idx = rmseList.indexOf(rmse) + 1
tempRMSE = rmse
}
I get following error, when I am trying to iterate list and assign current value to temp variable.
[error] found : Double.type
[error] required: Double
[error] tempRMSE = rmse
You've probably put the companion object for Double into a list instead of actually putting doubles there. Here's an example:
scala> val xs = List(Double)
xs: List[Double.type] = List(object scala.Double)
scala> var d: Double = 0
d: Double = 0.0
scala> for (x <- xs) { d = x }
<console>:10: error: type mismatch;
found : Double.type
required: Double
for (x <- xs) { d = x }
As to how you managed to put the companion object in instead of Double values, I don't know, because you didn't show us how you built the list. Maybe somehow using parens (Double) instead of brackets [Double] to specify the type?

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

Incrementing and getting value

Simple scala question. Consider the below.
scala> var mycounter: Int = 0;
mycounter: Int = 0
scala> mycounter += 1
scala> mycounter
res1: Int = 1
In the second statement I increment my counter. But nothing is returned. How do I increment and return something in one statement.
Using '+=' return Unit, so you should do:
{ mycounter += 1; mycounter }
You can too do the trick using a closure (as function parameters are val):
scala> var x = 1
x: Int = 1
scala> def f(y: Int) = { x += y; x}
f: (y: Int)Int
scala> f(1)
res5: Int = 2
scala> f(5)
res6: Int = 7
scala> x
res7: Int = 7
BTW, you might consider using an immutable value instead, and embrace this programming style, then all your statements will return something ;)
Sometimes I do this:
val nextId = { var i = 0; () => { i += 1; i} }
println(nextId()) //> 1
println(nextId()) //> 2
Might not work for you if you need sometime to access the value without incrementing.
Assignment is an expression that is evaluated to Unit. Reasoning behind it can be found here: What is the motivation for Scala assignment evaluating to Unit rather than the value assigned?
In Scala this is usually not a problem because there probably is a different construct for the problem you are solving.
I don't know your exact use case, but if you want to use the incrementation it might be in the following form:
(1 to 10).foreach { i =>
// do something with i
}

More on generic Scala functions

Trying to implement, in Scala, the following Haskell function (from Learn You a Haskell...) so that it works with Int, Double, etc.
doubleUs x y = x * 2 + y * 2
Note that this is similar to Scala: How to define "generic" function parameters?
Here's my attempt and error. Can someone explain what's happening and offer a solution. Thanks.
scala> def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A = numeric.plus(numeric.times(x,2),numeric.times(y,2))
<console>:34: error: type mismatch;
found : Int(2)
required: A
def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A = numeric.plus(numeric.times(x,2),numeric.times(y,2))
In addition to what #Dylan said, you can make it look a little less tedious by importing into scope the contents of Numeric implicit as shown below:
scala> def doubleUs[N](x: N, y: N)(implicit ev: Numeric[N]) = {
| import ev._
| x * fromInt(2) + y * fromInt(2)
| }
doubleUs: [N](x: N, y: N)(implicit ev: Numeric[N])N
scala> doubleUs(3, 4)
res9: Int = 14
scala> doubleUs(8.9, 1.2)
res10: Double = 20.2
You are using the Int literal 2 but scala is expecting the Numeric type A.
The Scala Numeric API has a utility function- def fromInt(x:Int): T. This is what you want to use, so replace your usage of 2 with numeric.fromInt(2)
def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A =
numeric.plus (numeric.times (x, numeric.fromInt (2)), numeric.times (y, numeric.fromInt (2)))
Also, since a Numeric instance defines an implicit conversion to an Ops, you can import numeric._ and then say x * fromInt(2) + y * fromInt(2).
You need some implicits in scope:
def doubleUs[A](x: A, y: A)(implicit num: Numeric[A]) = {
import num._
implicit def fromInt(i: Int) = num.fromInt(i)
x * 2 + y * 2
}
Dylan essentially answered, but for what it's worth, let me suggest to use the context bound syntax instead of the implicit argument (both are equivalent, and the former is automatically rewritten into the latter by the compiler).
def doubleUs[A : Numeric](x : A, y : A) : A = {
val num = implicitly[Numeric[A]]
import num.{plus,times,fromInt}
plus(times(x, fromInt(2)), times(y, fromInt(2)))
}

Scala methods ending in _=

I seem to remember Scala treating methods ending in _= specially, so something like this:
object X { var x: Int = 0; def y_=(n : Int) { x = n }}
X.y = 1
should call X.y_=(1). However, in 2.8.0 RC1, I get an error message:
<console>:6: error: value y is not a member of object X
X.y = 1
^
Interestingly, just trying to call the method without parentheses fails as well:
scala> X.y_= 1
<console>:1: error: ';' expected but integer literal found.
X.y_= 1
^
Am I misremembering something which does actually exist or did I just invent it out of whole cloth?
This is one of those corner cases in Scala. You cannot have a setter without a getter and vice versa.
The following works fine:
scala> object X {
| var x: Int = 0
| def y = x
| def y_=(n: Int) { x = n }
| }
defined module X
scala> X.y = 45
scala> X.y
res0: Int = 45
scala> object X { var x: Int = 0; def y_=(n : Int) { x = n }}
defined module X
scala>
scala> X y_= 1
scala> X.x
res1: Int = 1
scala> object X { var x: Int = _; def y = x ; def y_=(n: Int) { x = n } }
defined module X
scala> X.y = 1
scala> X.y
res2: Int = 1
scala>