Clarification on var and val in Scala - scala

I was expecting a compiler error with the following code:
object Test {
def main(args: Array[String]) : Unit = {
val x = 10
var y = x
val z = y
println("x: " + x)
println("y: " + y)
println("z: " + z)
y = 100
println("x: " + x)
println("y: " + y)
println("z: " + z)
}
}
However, the code compiles and I get back the following output:
x: 10
y: 10
z: 10
x: 10
y: 100
z: 10
What's going on?
When you initialize a val to a mutable value (or vice-versa), does it immediately copy it? Does it do this for any class? Is it a deep copy?

val is immutable reference to the instance in case of reference class (including String) and immutable value (which is copied, not shared on assignment), in case of value types (Int, Char, Double, ...)
var is mutable reference and mutable value respectively
In fact Java and many other languages has the very same semantics

Your example behaves the exact same way as C, java, python, or any other programming language.
I think you are really asking about the val/var immutable/mutable distinction. Here's a clearer example:
class A(var s: String) {
override def toString = s
}
val x = new A("first") // a new A object [Object1] is allocated, x points to it
var y = x // y is pointed to x's referent, which is [Object1]
val z = y // z is pointed to y's referent, which is [Object1]
println(x) // "first"
println(y) // "first"
println(z) // "first"
y = new A("second") // a new A object [Object2] is allocated, y points to it
println(x) // "first" // note that x is still pointing to the same object [Object1]
println(y) // "second"
println(z) // "first" // so is z
x.s = "third" // the string *inside* [Object1] is changed
println(x) // "third" // x still points to [Object1], which now contains "third"
println(y) // "second" // y still points to [Object2]
println(z) // "third" // z still points to [Object1], which now contains "third"
Saying y = will always point y at a new object, not change the current object that y points to. This means that saying y = can never change x or z.
If A were immutable (class A(s: String)), then the only difference is that the operation x.s = would be disallowed. Everything above that would be exactly the same.

Related

type mismatch in scala when using reduce

Can anybody help me understand what's wrong with the code below?
case class Point(x: Double, y: Double)
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.reduce(_.x + _.x)
val y = points.reduce(_.y + _.y)
val len = points.length
Point(x/len, y/len)
}
I get the error when I run it:
Error:(10, 30) type mismatch;
found : Double
required: A$A145.this.Point
val x = points.reduce(_.x + _.x)
^
reduce, in this case, takes a function of type (Point, Point) => Point and returns a Point.
One way to calculate the centroid:
case class Point(x: Double, y: Double)
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.map(_.x).sum
val y = points.map(_.y).sum
val len = points.length
Point(x/len, y/len)
}
If you want to use reduce you need to reduce both x and y in a single pass like this
def centroid(points: IndexedSeq[Point]): Point = {
val p = points.reduce( (s, p) => Point(s.x + p.x, s.y + p.y) )
val len = points.length
Point(p.x/len, p.y/len)
}
If you want to compute x and y independently then use foldLeft rather than reduce like this
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.foldLeft(0.0)(_ + _.x)
val y = points.foldLeft(0.0)(_ + _.y)
val len = points.length
Point(x/len, y/len)
}
This is perhaps clearer but does process the points twice so it may be marginally less efficient.

Functional Programming: Perimeter of a polygon.

I am trying to find the perimeter of a polygon in a functional way. I tried my best but I couldn't make it purely functional. This is my code:
object Solution {
def main(args: Array[String]) {
var x:Double = 0
val N = scala.io.StdIn.readInt
val points = scala.io.Source.stdin.getLines().take(N).map(x=>x).toList
for(i <- 0 to N-1){
if(i==N-1) x+=dist(List(points(i),points(0)))
else x += dist(List(points(i),points(i+1)))
}
println(x)
}
def dist(A: List[String]): Double = {
scala.math.sqrt(scala.math.pow((A(0).split(" ")(0).toDouble-A(1).split(" ")(0).toDouble),2) + scala.math.pow((A(0).split(" ")(1).toDouble-A(1).split(" ")(1).toDouble),2))
}
}
I enter the number of points of the polygon first and then enter Cartesian coordinates of each point in a new line.
Can anyone help me make it purely functional?
Start with separating concerns:
// dist should just take 2 points
def dist(a: (Double,Double), b: (Double,Double)): Double = ...
// calculate perimeter
def perimeter (points: List[(Double,Double)]): Double = {
// create a list of lines by connecting adjacent points
val lines = points zip (points.tail ++ List(points.head))
// aggregate the length of each line using foldLeft (/:)
(0d /: lines)((acc, line) => acc ++ dist(line._1, line._2))
}
def main (args: Array[String]) {
// main just needs to parse the lines
val points = ... // parse the points
println(perimeter(points))
}
Consider val n = 5 points
val points = (1 to n).map(_ => Math.random * 10).toArray
and a distance function, for example
def dist(a: Double, b: Double) = math.abs(a-b)
Then iterate continually (in circles) n times on (grouped) pairs of points to which we apply dist,
Iterator.continually(points)
.flatten
.sliding(2)
.take(n)
.map { case a :: b :: Nil => dist(a,b) }
.sum

Refactoring a small Scala function

I have this function to compute the distance between two n-dimensional points using Pythagoras' theorem.
def computeDistance(neighbour: Point) = math.sqrt(coordinates.zip(neighbour.coordinates).map {
case (c1: Int, c2: Int) => math.pow(c1 - c2, 2)
}.sum)
The Point class (simplified) looks like:
class Point(val coordinates: List[Int])
I'm struggling to refactor the method so it's a little easier to read, can anybody help please?
Here's another way that makes the following three assumptions:
The length of the list is the number of dimensions for the point
Each List is correctly ordered, i.e. List(x, y) or List(x, y, z). We do not know how to handle List(x, z, y)
All lists are of equal length
def computeDistance(other: Point): Double = sqrt(
coordinates.zip(other.coordinates)
.flatMap(i => List(pow(i._2 - i._1, 2)))
.fold(0.0)(_ + _)
)
The obvious disadvantage here is that we don't have any safety around list length. The quick fix for this is to simply have the function return an Option[Double] like so:
def computeDistance(other: Point): Option[Double] = {
if(other.coordinates.length != coordinates.length) {
return None
}
return Some(sqrt(coordinates.zip(other.coordinates)
.flatMap(i => List(pow(i._2 - i._1, 2)))
.fold(0.0)(_ + _)
))
I'd be curious if there is a type safe way to ensure equal list length.
EDIT
It was politely pointed out to me that flatMap(x => List(foo(x))) is equivalent to map(foo) , which I forgot to refactor when I was originally playing w/ this. Slightly cleaner version w/ Map instead of flatMap :
def computeDistance(other: Point): Double = sqrt(
coordinates.zip(other.coordinates)
.map(i => pow(i._2 - i._1, 2))
.fold(0.0)(_ + _)
)
Most of your problem is that you're trying to do math with really long variable names. It's almost always painful. There's a reason why mathematicians use single letters. And assign temporary variables.
Try this:
class Point(val coordinates: List[Int]) { def c = coordinates }
import math._
def d(p: Point) = {
val delta = for ((a,b) <- (c zip p.c)) yield pow(a-b, dims)
sqrt(delta.sum)
}
Consider type aliases and case classes, like this,
type Coord = List[Int]
case class Point(val c: Coord) {
def distTo(p: Point) = {
val z = (c zip p.c).par
val pw = z.aggregate(0.0) ( (a,v) => a + math.pow( v._1-v._2, 2 ), _ + _ )
math.sqrt(pw)
}
}
so that for any two points, for instance,
val p = Point( (1 to 5).toList )
val q = Point( (2 to 6).toList )
we have that
p distTo q
res: Double = 2.23606797749979
Note method distTo uses aggregate on a parallelised collection of tuples, and combines the partial results by the last argument (summation). For high dimensional points this may prove more efficient than the sequential counterpart.
For simplicity of use, consider also implicit classes, as suggested in a comment above,
implicit class RichPoint(val c: Coord) extends AnyVal {
def distTo(d: Coord) = Point(c) distTo Point(d)
}
Hence
List(1,2,3,4,5) distTo List(2,3,4,5,6)
res: Double = 2.23606797749979

Data Abstraction in Scala

We were given a problem in scala to define a procedure that that takes a line segment as an argument and returns its midpoint(the point whose coordinates are the average of the coordinates of the end points.) When I try to compile the program it gives me two errors, namely type mismatch errors in my midpointSegment method. I don't get why it requires a String. Can anyone point out my mistake? Below is my code.
class Point(x: Int, y: Int) {
def xCoord = x
def yCoord = y
def makeString(m: Point) = "Point" + "(" + x + "," + y + ")"
}
class LineSegment(x: Point, y: Point) {
def startSeg = x
def endSeg = y
def midpointSegment(m: LineSegment) = ((startSeg + m.startSeg) / 2,
(endSeg + m.endSeg) / 2)
def makeString(m: LineSegment) =
"LineSegment" + "(" + x.makeString(x) + "," + y.makeString(y) + ")"
}
object Mp5 {
def main(args: Array[String]): Unit = {
val aLine1 = new Point(1, 2)
val aLine2 = new Point(5, 4)
val aLineSegment1 = new LineSegment(aLine1, aLine2)
val aLineSegment2 = new LineSegment(new Point(-3, 5), new Point(8, -1))
println(aLine1.makeString(aLine1))
println(aLine2.makeString(aLine2))
println(aLineSegment1.makeString(aLineSegment1))
println(aLineSegment2.makeString(aLineSegment2))
println(aLineSegment1.midpointSegment(aLineSegment2))
}
}
You are trying to add two points, since startSeg and m.startSeg are points. You haven't defined how to do this, so the compiler seems to think you are adding strings (since anything can be added to a string, as in definition of toString). To be honest, I wouldn't expect this error if that's the entire code, and instead something about a missing + method.
For future reference: 1. provide the actual error message and stack trace; 2. you don't need to define methods like def xCoord = x in Scala, just write val x instead of simply x in class parameters; 3. read about case classes.

Scala: Using Sets for (non - primitive) co-odinate values

I'm using integer coordinates for hex grids as follows:
object Cood
{
val up = Cood(0, 2)
val upRight = Cood(1, 1)
val downRight = Cood(1, -1)
val down = Cood(0, - 2)
val downLeft = Cood(-1, -1)
val upLeft = Cood(- 1, 1)
val dirns: List[Cood] = List[Cood](up, upRight, downRight, down, downLeft, upLeft)
}
case class Cood(x: Int, y: Int)
{
def +(operand: Cood): Cood = Cood(x + operand.x, y + operand.y)
def -(operand: Cood): Cood = Cood(x - operand.x, y - operand.y)
def *(operand: Int): Cood = Cood(x * operand, y * operand)
}
Hexs and Sides both have coordinate values. Every Hex has 6 sides but some sides will be shared by 2 Hexs. Eg Hex(2, 2) and its upper neighbour Hex(2, 6) share Side(2, 4). So I want to apply set operations something like this:
val hexCoods: Set[Cood] = ... some code
val sideCoods: Set[Cood] = hexCoods.flatMap(i => Cood.dirns.map(_ + i).toSet)
But if I do this Cood will be treated as a reference type and the duplicate co-ordinates won't be stripped out. Is there any way round this?
Did you try it?
scala> Set.empty + Cood(1,1) + Cood(1,2) + Cood(1,1)
res0: scala.collection.immutable.Set[Cood] = Set(Cood(1,1), Cood(1,2))
Like #sschaef pointed out in the comments, case classes have automatically-generated equals and hashCode methods, which implement structural equality rather than just comparing identity. This means that you shouldn't get duplicates in your set, and sure enough the set in my test didn't have a duplicate entry.