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
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)
}
Let's say I have a type Pos (for position). In order to gain type-safety the column/row is not represented as Int but by types Col (column) and a Row:
case class Pos(col: Col, row: Row) {
def +(other: Pos): Pos = Pos(col + other.col, row + other.row)
}
It's possible to add two positions, which consists of summing columns and rows respectively.
The definition of types Col and Row would look like this:
object Row {
def apply(value: Int) = new Row(value)
val zero = new Row(0)
}
object Col {
def apply(value: Int) = new Col(value)
val zero = new Col(0)
}
class Row(val value: Int) extends AnyVal {
def +(other: Row): Row = Row(this.value + other.value)
}
class Col(val value: Int) extends AnyVal {
def +(other: Col): Col = Col(this.value + other.value)
}
This is all fine, but I have the feeling of repeating myself. The definitions are almost identical.
Could I do something to generalize them?
If you introduce Scalaz and create Monoid instances for Row and Col, you may not reduce your boilerplate, but it would shorten your definition of zero and append some:
case class Col(i: Int) extends AnyVal
case class Row(i: Int) extends AnyVal
implicit object rowMonoid extends Monoid[Row] {
def zero = Row(0)
def append(a: Row, b: => Row) = Row(a.i |+| b.i)
}
implicit object colMonoid extends Monoid[Col] {
def zero = Col(0)
def append(a: Col, b: => Col) = Col(a.i |+| b.i)
}
And Monoids are composable, so if you stored Rows and Cols in a map, or tuple or the like, you could just compose them, without hitting the individual elements:
val pt1 = (Row(4), Col(15))
val pt2 = (Row(14), Col(5))
val res = pt1 |+| pt2
println(res) // (Row(18),Col(20))
I think simplifying the usage will save you more code overall than worrying about trimming down the definitions, assuming Row and Col are used and added often.
You can define a common trait for Both Row and Col classes:
trait Element {
val value : Int
def init(value: Int): Element
def +(other: Element) = init(value + other.value)
}
and then use case classes so that you take advantage of the companion object's apply method:
case class Row(value: Int) extends Element {
def init(v: Int) = Row(v)
}
case class Col(value: Int) extends Element {
def init(v: Int) = Col(v)
}
So now you can add them like that:
case class Pos(col: Element, row: Element) {
def +(other: Pos): Pos = Pos(col + other.col, row + other.row)
}
val p1 = Pos(Col(1), Row(2))
val p2 = Pos(Col(1), Row(2))
p1 + p2 //res2: Pos = Pos(Col(2),Row(4))
However, this allows to create a position with only rows
val p3 = Pos(Row(2), Row(3))
p1 + p3 //res3: Pos = Pos(Col(3),Row(5))
So a second step is to bound your Element type's + method.
trait Element[T <: Element[_]] {
val value : Int
def init(value: Int): Element[T]
def +(other: Element[T]) = init(value + other.value)
}
case class Row(value: Int) extends Element[Row] {
def init(v: Int) = Row(v)
}
case class Col(value: Int) extends Element[Col] {
def init(v: Int) = Col(v)
}
case class Pos(col: Element[Col], row: Element[Row]) {
def +(other: Pos): Pos = Pos(col + other.col, row + other.row)
}
What you get is that now a row should only add elements of a row type and a Col should only add elements of a Col type. You can still add two positions:
val p1 = Pos(Col(1), Row(2))
val p2 = Pos(Col(1), Row(2))
p1 + p2 //res0: Pos = Pos(Col(2),Row(4))
but this will not compile:
val p3 = Pos(Row(2), Row(3))
You can use type variable in your trait
Something like this
trait TableElement{
type T
def +(t:T):T
}
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.
Is it possible to initialize a class parameter with a function in Scala?
Example:
def square(x: Int) = x*x
class Foo(val x: Int = square(x))
This doesn't compile but I hope you get the idea.
Hard to guess what you're trying to achieve, but let me have a go:
class Foo private (val x: Int)
object Foo {
def apply(x: Int) = new Foo(square(x))
}
Note that if you try this in the REPL, you must enter both the class and its companion object at the same time (in paste mode, via :pa), or the object Foo won't have access to the private class constructor.
This applies the square function to the parameter x before creating a Foo instance:
scala> Foo(3).x
res1: Int = 9
This is not possible because you try to calculate x based on x (without having any kind of base case). You could do the following:
class Foo(_x: Int) {
val x = square(_x)
}
println(new Foo(10).x) // 100
EDIT
You could also generalise this and implicitly pass a function to the class constructor that transforms x:
implicit val square = (x: Int) => x*x
class Foo(private val _x: Int)(implicit f: Int => Int) {
val x = f(_x)
}
println(new Foo(10).x) // 100
This unfortunately doesn't compile as-is (Scala 2.9.2, 2.10.0), because there is another implicit in scope (Predef.conforms). I don't know how to overcome this ambiguity, but it should certainly be possible.
Here it is.. you can initialize a class with a function ! :)
class Foo(f : Int => Int)
def square(x : Int) = x*x
val foo = new Foo(square)
Or Probably you must be looking for this.
class Foo(f : Int => Int, _p1 : Int){
val p1 = f(_p1)
}
def square(x : Int) = x*x //> square: (x: Int)Int
def add2(x : Int) = x+2 //> add2: (x: Int)Int
val fooSqr = new Foo(square,5)
fooSqr.p1 //> res0: Int = 25
val fooAdd2 = new Foo(add2,5)
fooAdd2.p1 //> res1: Int = 7
In general you can use arbitrary expressions when defining the default value (source).
Your problem is that you can not use x on the right hand side of the initialization, because x is probably neither declared nor initialized at that point.
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
}
}