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.
Related
I'm doing the following function to return a new figure from another, but Scala is inferring the result as Figure and I want it to be the figure in particular, as a circle, etc.
How could I do to infer the particular figure? I have been told to use generics to solve it, how would this be?
trait Figure {
def x:Int
def y:Int
}
case class Circle(x:Int, y: Int, radio: Double)
extends Figure
case class Rectangle(x:Int, y: Int, width: Int, high: Int)
extends Figure
object Motor {
def move[T](x: Int, y: Int, figure: T) :Figure = figure match {
case Circle(xPos, yPos, radio) => Circle(xPos+x, yPos+y, radio)
case Rectangle(xPos, yPos, width, high) => Rectangle(xPos+x, yPos+y, width, high)
}
}
Here's is a more concise, perhaps a bit less intimidating version of Sarvesh Kumar Singh's suggestion to use a typeclass. I think that is the best approach all around. It gives you typesafe functionality while letting you keep your basic types very simple.
trait Figure {
def x:Int
def y:Int
}
case class Circle(x:Int, y: Int, radius: Double) extends Figure
case class Rectangle(x:Int, y: Int, width: Int, height: Int) extends Figure
trait Movable[T] {
def move( x: Int, y: Int, movable: T ) : T
}
implicit final object CircleIsMovable extends Movable[Circle] {
def move( x: Int, y: Int, c: Circle ) = Circle( c.x + x, c.y + y, c.radius )
}
implicit final object RectangleIsMovable extends Movable[Rectangle] {
def move( x: Int, y: Int, r: Rectangle ) = Rectangle( r.x + x, r.y + y, r.width, r.height )
}
object Motor {
def move[T : Movable](x: Int, y: Int, movable: T) : T = implicitly[Movable[T]].move( x, y, movable )
}
Then...
scala> Motor.move(10,10,Circle(0,0,1))
res1: Circle = Circle(10,10,1.0)
scala> Motor.move(10,10,Rectangle(0,0,1,1))
res2: Rectangle = Rectangle(10,10,1,1)
You should make it so that the "move" happens on the type T itself and return type T. But then the compiler will complain about not being sure that you are returning a T because the actual type of T will be determined for the use of move and compiler has no evidence to determine that it was a Circle as match-case is a runtime thing.
Which means you need to provide evidence which can be used at compile-time to move any instance of type T.
import scala.language.implicitConversions
trait Figure {
def x:Int
def y:Int
}
case class Circle(x:Int, y: Int, radio: Double)
extends Figure
case class Rectangle(x:Int, y: Int, width: Int, high: Int)
extends Figure
Now, let us build the required evidence which will be used to "enrich" our Figure instances
trait MoveSupport[F <: Figure] {
val f: F
def move(x: Int, y: Int): F
}
object MoveSupport {
class CircleMoveSupport(val f: Circle) extends MoveSupport[Circle] {
override def move(x: Int, y: Int): Circle = f.copy(x = f.x + x, y = f.y + y)
}
class RectangleMoveSupport(val f: Rectangle) extends MoveSupport[Rectangle] {
override def move(x: Int, y: Int): Rectangle = f.copy(x = f.x + x, y = f.y + y)
}
implicit def toCircleMoveSupport(circle: Circle) = new CircleMoveSupport(circle)
implicit def toRectangleMoveSupport(rectangle: Rectangle) = new RectangleMoveSupport(rectangle)
}
Now, we can use these evidence to "enrich" our Figure types to have move support.
import MoveSupport._
val circle = Circle(1, 1, 1)
// circle: Circle = Circle(1,1,1.0)
val circle2 = circle.move(1, 1)
// circle2: Circle = Circle(2,2,1.0)
Or, you can build your Motor using these evidence.
object Motor {
import MoveSupport._
def move[T <: Figure](x: Int, y: Int, figure: T)(implicit ev: T => MoveSupport[T]): T = figure.move(x, y)
}
val c = Circle(1, 1, 1)
// circle: Circle = Circle(1,1,1.0)
val c1 = Motor.move(1, 1, c)
// circle1: Circle = Circle(2,2,1.0)
Maybe what you are after is something like
object Motor {
def move[T <: Figure](x: Int, y: Int, figure: T): T = {
val moved = figure match {
case Circle(xPos, yPos, radio) => Circle(xPos+x, yPos+y, radio)
case Rectangle(xPos, yPos, width, high) => Rectangle(xPos+x, yPos+y, width, high)
}
moved.asInstanceOf[T]
}
}
You may want to consider moving the implementation of move to the various classes. Here is an example that uses abstract types to enable the method to return the type of the object:
trait Figure {
def x: Int
def y: Int
type Self <: Figure
def move(dx: Int, dy: Int): Self
}
case class Circle(x: Int, y: Int, radius: Double) extends Figure {
type Self = Circle
def move(dx: Int, dy: Int): Circle = copy(x = x + dx, y = y + dy)
}
case class Rectangle(x: Int, y: Int, widht: Int, height: Int) extends Figure {
type Self = Rectangle
def move(dx: Int, dy: Int): Rectangle = copy(x = x + dx, y = y + dy)
}
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
I am just starting out with Scala, and working on some tutorials. I came across companion object, and using them as factory. I tried several things out. However I am not getting the following to work properly. Cant get my head around it..
import math._
abstract class Point{
// ...
}
object Point{
private class PointInt(val x:Int,val y:Int) extends Point{
def +(that:PointInt) = new PointInt(this.x + that.x, this.y + that.y)
def distance(that:PointInt) =
sqrt(pow((this.x - that.x), 2) + pow((this.y - that.y), 2))
}
private class PointDouble(val x:Double,val y:Double) extends Point{
def +(that:PointDouble) = new PointDouble(this.x + that.x, this.y + that.y)
def distance(that:PointDouble) =
sqrt(pow((this.x - that.x), 2) + pow((this.y - that.y), 2))
}
def apply(x:Int,y:Int):Point = new PointInt(x,y)
def apply(x:Double,y:Double):Point = new PointDouble(x,y)
}
val a = Point(1,2)
val b = Point(3,4)
val c = a+b // does not work...
Just trying to add up two integer Points, like I defined it in the methods... Does anyone know what I am doing wrong??
EDIT: I was was trying to wrap the following (working) class in an Factory.
class Point(val x:Int,val y:Int){
def +(that:Point) = new Point(this.x + that.x, this.y + that.y)
def distance(that:Point) = sqrt(pow((this.x - that.x),2) + pow((this.y - that.y),2))
}
val a = new Point(1,2) //> a : week1.OU2.Point = week1.OU2$Point#73e48fa7
val b = new Point(3,4) //> b : week1.OU2.Point = week1.OU2$Point#677bb8fe
val c = a+b //> c : week1.OU2.Point = week1.OU2$Point#6bae60c5
c.x //> res0: Int = 4
c.y //> res1: Int = 6
I am not quite sure which constraints are actually imposed on you, for example, which classes should/must be private, but using F-bounded polymorphism might be a stepping stone to your desired solution.
/* Simplified interface (adding sqrt is straight-forward) */
abstract class Point[P <: Point[P]] {
def +(that: P): P
}
/* Two implementations */
class PointInt(val x:Int,val y:Int) extends Point[PointInt] {
def +(that:PointInt) = new PointInt(this.x + that.x, this.y + that.y)
}
class PointDouble(val x:Double,val y:Double) extends Point[PointDouble] {
def +(that:PointDouble) = new PointDouble(this.x + that.x, this.y + that.y)
}
/* Companion object */
object Point {
def apply(x:Int,y:Int) = new PointInt(x,y)
def apply(x:Double,y:Double) = new PointDouble(x,y)
}
/* Use cases */
val a = Point(1,2)
val b = Point(3,4)
val c = a+b // ok
val d = Point(1.0, 2.5)
val e = c+d // error: type mismatch
Notice, however, that this won't help you in case you want to hide your implementations, i.e., make them private and declare public interfaces using the generic Point only - as others pointed out already.
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)
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
}
}