Data Abstraction in Scala - 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.

Related

value - is not a member of type parameter T | Scala Error

I am using Scala 2.13.
I wrote the following code representing a 2D Point which works on only scala.math.Numeric types:
class Point[T: Numeric](val x: T, val y: T) {
def getDistance(otherPoint: Point[T]): Double = {
math.sqrt(math.pow(otherPoint.x - x, 2) + math.pow(otherPoint.y - y, 2))
}
override def toString = "(" + x + "," + y + ")"
}
in the 4th line, I get the error "value - is not a member of type parameter T", click to see the location where error occurs:
click to see error location
Where am I going wrong here? (I am new to generics, type bounds in scala)
Problem 1:
To use mathematical operators given a Numeric bound, you need to
import Numeric.Implicits._
(and Fractional/Integral.Implicits._ to get division operations). Without it you need to do something like
Numeric[T].minus(otherPoint.x, x)
or to give a name to the implicit Numeric parameter instead of using a context bound. With the import you can just write
otherPoint.x - x
The import can be declared at any scope: usually at the top of the file, but it can go inside the method if you only need it once.
Problem 2:
math.pow works only on Double, and there's no equivalent function for all Numerics in the standard library. So convert to Double using toDouble method (you could define a generic squaring function, but not really square root).
First, you need an extra import to enable the convenient symbol ops on a Numeric.
After that, feed pow() a parameter type that it understands.
class Point[T: Numeric](val x: T, val y: T) {
import Numeric.Implicits._
def getDistance(otherPoint: Point[T]): Double = {
math.sqrt(math.pow((otherPoint.x - x).toDouble, 2) +
math.pow((otherPoint.y - y).toDouble, 2))
}
override def toString = "(" + x + "," + y + ")"
}

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.

Scala Implicit Conversion Function Name Clashes

I am working with a simple complex number case class in Scala and would like to create an add function that works between complex numbers, doubles and ints. Below is a simple example of a working solution:
case class Complex(re: Double, im: Double)
implicit def toComplex[A](n: A)(implicit f: A => Double): Complex = Complex(n, 0)
implicit class NumberWithAdd[A](n: A)(implicit f: A => Complex) {
def add(m: Complex) = Complex(n.re + m.re, n.im + m.im)
}
Note I am deliberately not including the add function in the complex case class. Using the above I can do all of this:
scala> val z = Complex(1, 2); val w = Complex(2, 3)
z: Complex = Complex(1.0,2.0)
w: Complex = Complex(2.0,3.0)
scala> z add w
res5: Complex = Complex(3.0,5.0)
scala> z add 1
res6: Complex = Complex(2.0,2.0)
scala> 1 add z
res7: Complex = Complex(2.0,2.0)
I'd like to use '+' instead of 'add, but however this does not work. I get the following error:
Error:(14, 4) value + is not a member of A$A288.this.Complex
z + 1
^
Both z + w and 1 + z still work however.
What I'd like to know is why does changing the function name from 'add' to '+' break this? Is there an alternate route to getting this functionality (without simply putting the add function in the complex case class)? Any help would be appreciated.
Edit - Motivation
I'm playing around with monoids and other algebraic structures. I would like to be able to generalise the '...WithAdd' function to automatically work for any class that has a corresponding monoid:
trait Monoid[A] {
val identity: A
def op(x: A, y: A): A
}
implicit class withOp[A](n: A)(implicit val monoid: Monoid[A]) {
def +(m: A): A = monoid.op(n, m)
}
case class Complex(re: Double, im: Double) {
override def toString: String = re + " + " + im + "i"
}
class ComplexMonoid extends Monoid[Complex] {
val identity = Complex(0, 0)
def op(z: Complex, w: Complex): Complex = {
Complex(z.re + w.re, z.im + w.im)
}
}
implicit val complexMonoid = new ComplexMonoid
Using the above I can now do Complex(1, 2) + Complex(3, 1) giving Complex = 4.0 + 3.0i. This is great for code reuse as I could now add extra functions to the Monoid and withAdd function (such as appling op n times to an element, giving the power function for multiplication) and it would work for any case class that has a corresponding monoid. It is only with complex numbers and trying to incorporate doubles, ints, etc., that I then run into the problem above.
I would use a regular class, not a case class. Then it would be easy to create methods to add or subtract these Complex numbers, like:
class Complex(val real : Double, val imag : Double) {
def +(that: Complex) =
new Complex(this.real + that.real, this.imag + that.imag)
def -(that: Complex) =
new Complex(this.real - that.real, this.imag - that.imag)
override def toString = real + " + " + imag + "i"
}
As the source page shows, it will now support something that looks like operator overloading (it's not, because + and - are functions and not operators).
The problem with implicit class NumberWithAdd and its method + is that the same method also exist in number classes such as Int and Double. The + method of NumberWithAdd basically allows you to start with a number that can be casted to Complex and add a Complex object to that first item. That is, the left hand value can be anything (as long as it can be converted) and the right hand value must be Complex.
That works great for w + z (no need to convert w) and 1 + z (implicit conversion for Int to Complex is available). It fails for z + 1 because + is not available in the class Complex .
Since z + 1 is actually z.+(1), Scala will look for other possible matches for +(i: Int) in classes that Complex can be converted into. It also checks NumberWithAdd, which does have a + function but that one required a Complex as right hand value. (It would match a function that requires an Int as right hand value.) There are other functions named + that do accept Int, but there's no conversion from Complex to what those functions want as left hand values.
The same definition of + does work when it's in the (case) class Complex. In that case, both w + z and z + 1 simply use that definition. The case 1 + z is now a little more complicated. Since Int does not have a function + that accepts a Complex value, Scala will find the one that does (in Complex) and determines whether or not it is possible to convert Int into Complex. That is possible using the implicit functions, the conversion takes place and the function is executed.
When the function + in the class NumberWithAdd is renamed add, there's no confusion with functions in Int because Int does not have a function +. So Scala will try harder to apply the function add and it will do the Int to Complex conversion. It will even do that conversion when you try 1 add 2.
Note: My explanations may not fully describe the actual inner workings.

Clarification on var and val in 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.

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.