How do I expose Scala constructor arguments as public members? - scala

Look at this example:
class Point(x: Double, y: Double){
override def toString = "x: " + x + ", y: " + y
def +(sourcePoint: Point) : Point = {
return new Point(x + sourcePoint.x, y + sourcePoint.y
}
}
As you can see I want to define a + operator method on the Point class. But this won't work
because in that method, x and y can't be accessed on the sourcePoint local variable since they are private, so I changed the example into this:
class Point(_x: Double, _y: Double){
var x = _x
var y = _y
override def toString = "x: " + x + ", y: " + y
def +(sourcePoint: Point) : Point = {
return new Point(x + sourcePoint.x, y + sourcePoint.y)
}
}
That obviously worked, however is there an easier way to define these variables instead of going from _x -> x and _y -> y.
Thanks for help and time! :)

Yes, there is:
class Point(val x: Int, val y: Int)

using val is valid but then the parameter becomes final (constant).
If you want to be able to reassign the value you should use var instead. So
class Point(var x: Int, var y: Int)

Related

When to use override in Scala class?

Here's an example that confused me a lot.
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
}
}
class Location(override val xc: Int,
override val yc: Int,
val zc: Int) extends Point(xc, yc) {
var z: Int = zc
def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
println ("z 的坐标点 : " + z);
}
}
Why does the method move not need an override modifier? It isn't an abstract method in class Point, it should be decorated with "override", I think. Actually, when I add an "override", error happens.
And for xc, yc, why "override" is a nessesary?
I'm really confused with that.
I have python experience and very little Java experience.
Any help will be appreciated, thanks!
for xc, yc, why "override" is a nessesary?
Nope, its not necessary. In your case you're making it val again in your child class, which is not necessary since you already defined them as val in parent class. (simply remove val from child class)
scala> class Point(val xc: Int, val yc: Int) {}
defined class Point
scala> class Location(xc: Int, yc: Int, val zc :Int) extends Point(xc, yc){}
defined class Location
Why the method "move" doesn't need an "override"?
Because your move method in Parent class is not an abstract method
or your signature is different in child class than parent class.
eg.
abstract class Point(val xc: Int, val yc: Int) {
abstract def doWhatever() : Unit
}
class Location(xc: Int, yc: Int, val zc: Int) extends Point(xc, yc) {
override def doWhatever(): Unit = ??? // override is optional
}
You could have aldo overridden if the signature was same, so that when you call childClass.move(), the overridden method is invoked.
class Point(val xc: Int, val yc: Int) {
def move() = println("parent::whatever")
}
class Location(xc: Int, yc: Int, val zc: Int) extends Point(xc, yc) {
override def move() = println("child::whatever") //override is required
}
example invoking move method,
for a parent,
scala> val point = new Point(1, 2)
point: Point = Point#66813e6e
scala> point.move()
parent::whatever
for a child,
scala> val location1 = new Location(1, 2, 3)
location1: Location = Location1#233db8e9
scala> location1.move()
child::whatever

toString function in Scala

I'm new to Scala, I was reading about scala from the following source: http://docs.scala-lang.org/tutorials/tour/classes
It had the following code:
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
x = x + dx
y = y + dy
}
override def toString: String =
"(" + x + ", " + y + ")"
}
object Classes {
def main(args: Array[String]) {
val pt = new Point(1, 2)
println(pt)
pt.move(10, 10)
println(pt)
}
}
The output is:
(1, 2)
(11, 12)
I wanted to ask how did the println(pt) function printed the result (1,2)? Should we not call pt.toString() to print the result as shown?
There's an overload of println that accepts a value of type Any (in Predef.scala):
def println(x: Any) = Console.println(x)
Deep inside, it calls x.toString() to get the string to print.

How do I satisfy IntelliJ IDEA's expectation that my scala class's companion object's declaration be tested?

case class Point(x: Double = 0,
y: Double = 0,
z: Double = 0) extends Point3D(x, y, z) {
def +(that: Point): Point = new Point(x + that.x, y + that.y, z + that.z)
def -(that: Point): Point = new Point(x - that.x, y - that.y, z - that.z)
def *(that: Point): Point = new Point(x * that.x, y * that.y, z * that.z)
def /(that: Point): Point = new Point(x / that.x, y / that.y, z / that.z)
}
object Point {
def apply(p3d: Point3D) = new Point(p3d.getX, p3d.getY, p3d.getZ)
}
IntelliJ is giving this code 92% coverage because the line object Point { is being counted in coverage, but I cannot figure out why or how to satisfy it's expectation. I have tried comparing it to something, tried adding another method and calling that... No such luck, and I am out of ideas.
EDIT: Here is the test code.
import javafx.geometry.Point3D
import org.scalatest._
class test_Point extends FlatSpec with Matchers {
val u = Point(100, 200, 300)
val v = Point(623, -85, 300)
it should "supply zero-valued defaults" in {
val p = Point()
p.x should be (0)
p.y should be (0)
p.z should be (0)
}
it should "be constructable from base class" in {
val p = Point(new Point3D(0, 0, 0))
}
it should "implement + operator" in {
val w = Point(u.x+v.x, u.y+v.y, u.z+v.z)
u + v should be (w)
}
it should "implement - operator" in {
val w = Point(u.x-v.x, u.y-v.y, u.z-v.z)
u - v should be (w)
}
it should "implement * operator" in {
val w = Point(u.x*v.x, u.y*v.y, u.z*v.z)
u * v should be (w)
}
it should "implement / operator" in {
val w = Point(u.x/v.x, u.y/v.y, u.z/v.z)
u / v should be (w)
}
}
Since Point is a case class, the companion object will automatically be populated with an apply method taking, in this case, 3 doubles. It may be this method that is not being covered. There is also an unapply method, and the case class itself will have equals, hashcode, toString and copy methods created for it, which you might need to cover.

Constructor parameters with same name as atributes

In Java, I can do this:
class Point{
int x, y;
public Point (int x, int y){
this.x = x;
this.y = y;
}
}
How can I do the same thing in Scala (use the same names in constructor arguments and in class attributes):
class Point(x: Int, y: Int){
//Wrong code
def x = x;
def y = y;
}
Edit
I'm asking this because the code below doesn't work
class Point(x: Int, y: Int) {
def +(that: Point): Point = new Point(this.x + that.x, this.y + that.y)
}
But the following one works:
class Point(px: Int, py: Int) {
def x = px
def y = py
def +(that: Point): Point = new Point(this.x + that.x, this.y + that.y)
}
In Scala the parameters of the constructor become public attributes of the class if declared as a var or val.
scala> class Point(val x: Int, val y: Int){}
defined class Point
scala> val point = new Point(1,1)
point: Point = Point#1bd53074
scala> point.x
res0: Int = 1
scala> point.y
res1: Int = 1
Edit to answer the question in comments "if they were private fields, shouldn't my first code snipped after the edit have worked?"
The constructor class Point(x: Int, y: Int) generates object-private fields which only allow methods of the Point class to access the fields x and y not other objects of type Point. that in the + method is another object and is not allowed access with this definition. To see this in action define add a method def xy:Int = x + y which does not generate a compile error.
To have x and y accessible to the class use a class-private field which is as follows:
class Point(private val x: Int, private val y: Int) {
def +(that: Point): Point = new Point(this.x + that.x, this.y + that.y)
}
Now they are not accessible outside of the class:
scala> val point = new Point(1,1)
point: Point = Point#43ba9cea
scala> point.x
<console>:10: error: value x in class Point cannot be accessed in Point
point.x
^
scala> point.y
<console>:10: error: value y in class Point cannot be accessed in Point
point.y
You can see this in action by using scalac -Xprint:parser Point.scala.
You don't need to; the "arguments" in the class declarations are all you need in Scala.

Scala constructor overload?

How do you provide overloaded constructors in Scala?
It's worth explicitly mentioning that Auxiliary Constructors in Scala must either call the primary constructor (as in landon9720's) answer, or another auxiliary constructor from the same class, as their first action. They cannot simply call the superclass's constructor explicitly or implicitly as they can in Java. This ensures that the primary constructor is the sole point of entry to the class.
class Foo(x: Int, y: Int, z: String) {
// default y parameter to 0
def this(x: Int, z: String) = this(x, 0, z)
// default x & y parameters to 0
// calls previous auxiliary constructor which calls the primary constructor
def this(z: String) = this(0, z);
}
class Foo(x: Int, y: Int) {
def this(x: Int) = this(x, 0) // default y parameter to 0
}
As of Scala 2.8.0 you can also have default values for contructor- and method parameters. Like this
scala> class Foo(x:Int, y:Int = 0, z:Int=0) {
| override def toString() = { "Foo(" + x + ", " + y + ", " + z + ")" }
| }
defined class Foo
scala> new Foo(1, 2, 3)
res0: Foo = Foo(1, 2, 3)
scala> new Foo(4)
res1: Foo = Foo(4, 0, 0)
Parameters with default values must come after the ones with no default values in the parameter list.
While looking at my code, I suddenly realized that I did kind of an overload a constructor. I then remembered that question and came back to give another answer:
In Scala, you can’t overload constructors, but you can do this with functions.
Also, many choose to make the apply function of a companion object a factory for the respective class.
Making this class abstract and overloading the apply function to implement-instantiate this class, you have your overloaded “constructor”:
abstract class Expectation[T] extends BooleanStatement {
val expected: Seq[T]
…
}
object Expectation {
def apply[T](expd: T ): Expectation[T] = new Expectation[T] {val expected = List(expd)}
def apply[T](expd: Seq[T]): Expectation[T] = new Expectation[T] {val expected = expd }
def main(args: Array[String]): Unit = {
val expectTrueness = Expectation(true)
…
}
}
Note that I explicitly define each apply to return Expectation[T], else it would return a duck-typed Expectation[T]{val expected: List[T]}.
Try this
class A(x: Int, y: Int) {
def this(x: Int) = this(x, x)
def this() = this(1)
override def toString() = "x=" + x + " y=" + y
class B(a: Int, b: Int, c: String) {
def this(str: String) = this(x, y, str)
override def toString() =
"x=" + x + " y=" + y + " a=" + a + " b=" + b + " c=" + c
}
}