Passing parameters to a trait - scala

I want to model the game of chess.
For that, I want to make an abstract class, Piece which takes a player and a position as arguments. From that, I want to extend to other classes such as Pawn:
trait Piece(player: Int, pos: Pos) = {
def spaces(destination: Pos): List[Pos]
}
case class Pawn extends Piece = {
//some other code
}
However, I think I'm not allowed to pass parameters to a trait, like this trait Piece(player: Int, pos: Pos).
So how can I have an abstract class Piece that has fields?

You could use an abstract class
abstract class Piece(player: Int, pos: Pos) {
...
}
case class Pawn(player: Int, pos: Pos) extends Piece(player, pos)
Or (probably better) you define those members abstractly in a trait
trait Piece {
def player: Int
def pos: Pos
...
}
case class Pawn(player: Int, pos: Pos) extends Piece

Dotty allows traits to have parameters, just like classes have parameters.
trait Greeting(val name: String) {
def msg = s"How are you, $name"
}
class C extends Greeting("Bob") {
println(msg)
}

I wasn't happy with the accepted answer for my use-case so I did the following. Note that you have two possibilities here for this same approach:
trait Piece {
// these can be referred to within this trait to implement reusable code
val player: Int
val pos: Pos
def spaces(destination: Pos): List[Pos] = {
// use player and pos at will e.g.
List(pos, destination)
}
}
case class Pawn(playerArg: Int, posArg: Pos) extends Piece = {
// now override those with whatever you like
override val player: Int = playerArg
override val pos: Pos = posArg
//some other code
}
The second alternative is to use and override methods instead e.g. def getPlayer: Int.
Yet another possibility is to use implicit on the trait methods that would require accessing those attributes but I'm not a big fan of this approach.
That said, apparently they have been thinking about it SIP-25 Trait Parameters.

Related

Comparisons between generic types in Scala

Consider the following segment of code -
abstract class Vehicle {
val name: String
}
case class Car(name: String) extends Vehicle
case class Truck(name: String) extends Vehicle
abstract class VehicleContainer[T <: Vehicle] {
def compare(that: VehicleContainer[T]): Int
}
class CarContainer(wheels: Int) extends VehicleContainer[Car] {
override def compare(that: CarContainer): Int = ???
}
The intention here is to have a compare method on the VehicleContainer that can be defined for each specific instance of VehicleContainer. The compare method comparison clause needs to be unique for each instance, because it could be comparing using attributes specific to that instance and hence not defined in the abstract base class VehicleContainer.
The trouble is that this does not work in it's current form, i.e. the override for compare is illegal. What I am not able to understand is how to accomplish this - define a base class that indicates that the sub classes need to implement a compare method, where the method argument to that compare method is that sub class itself. Would appreciate a pointer to the right concept here if it's some straightforward generics concept that I am missing here.
Thanks!
One way to solve your problem could be use of F-bounded polymophism. You would just need one additional type parameter:
abstract class Vehicle {
val name: String
}
case class Car(name: String) extends Vehicle
case class Truck(name: String) extends Vehicle
abstract class VehicleContainer[T <: Vehicle, V <: VehicleContainer[T, V]] {
def compare(that: V): Int
}
class CarContainer(wheels: Int) extends VehicleContainer[Car, CarContainer] {
override def compare(that: CarContainer): Int = ???
}

Enforce that all subclasses implement a given type class

Given a superclass or trait, and assuming an open hierarchy, how can I enforce that all extending classes implement a particular type class?
For instance, assuming the type class Default
trait Default[T] { def default: T }
and some trait Super:
trait Super { }
I would like to enforce that the following (by itself) is not allowed:
class A(val i: Int) extends Super
...while the following is:
class B(val i: Int) extends Super
implicit val bHasDef = new Default[B] { def default = B(42) }
Assuming the above is possible, can I then access the type class evidence for the subtypes from a method within Super? I.e, something like:
trait Super {
def magic: Default[this.type] = ???
}
I hardly think you can enforce that, at least in a simple enough way, maybe it's possible with something more complex like shapeless.
What I would do is add some modifications to the super trait and make it take a self reference to Default
trait Default[T] { def default: T }
trait Super[T] {
self: Default[T] =>
}
class B(val i: Int) extends Super[Int] with Default[Int] {
override def default: Int = ???
}
class A(val i: Int) extends Super[Int] // doesn't compile, needs a Default
This should also solve the second part of your question, the disadvantage is that now one trait is bundled to the other.

Custom and multiple constructor inheritance in Scala?

As I understand the semantics of a custom constructor may be typically added to a class via a companion object. Is there then, any way to inherit a custom constructor while inheriting a class?
On the one hand I have found that companion objects are not synthetically inherited along a case class, and on the other, I am not aware of a way of creating custom constructors inside a class itself, so that they are inherited. And yet inheriting custom constructors seems to be a perfectly valid use case to me. So is it supported in some (straightforward) way in Scala?
A naive demonstration of intent:
class A {}
object A {
def apply(n: Int) = {
println(n)
new A
}
}
class B extends A {}
object Test {
val a1 = A
val a2 = A(3)
val b1 = B // compile error
val b2 = B(3) // compile error
P.S. I have even found the arcane/deviant technique of defining this custom constructors result in a custom constructor that does not in actuality get inherited (it does work for just creating custom constructors, but quite oddly and unfortunately those do not get inherited). Demonstrating code:
class A {
def this(n: Int) = {
this
println(n)
}
}
class B extends A {}
object Test {
val a1: A = new A
val a2: A = new A(3)
val b1 = new B
val b2 = new B(3) // compile error
}
Clarification of Intent Edit:
consider "constructor" and "companion factory methods" interchangeable for the sake of this question.
You can't inherit constructors directly, and because you can't you also can't inherit things that use them without a little bit of work. But you can abstract away anything beyond the constructor call.
Let's suppose we have
class Foo(text: String) {
override def toString = "Foo: " + text
}
object Foo {
def apply(text: String) = new Foo(text) // Auto-generated for case class
def apply(i: Int) = new Foo(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
and we then decide to
class Bar(text: String) extends Foo(text) {
override def toString = "Bar: " + text
}
Now, what do we do about object Bar? Instead of writing all the logic over again, we create a trait to separate and abstract the object creation from the computation of the constructor parameter(s):
trait FooCompanionLike[A <: Foo] {
def apply(text: String): A // I am abstract!
def apply(i: Int): A = apply(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
Now we can
object Foo extends FooCompanionLike[Foo] {
def apply(text: String) = new Foo(text)
}
object Bar extends FooCompanionLike[Bar] {
def apply(text: String) = new Bar(text)
}
So you can't completely escape boilerplate, but you can reduce it to extending from a trait and a single method call.
If you do it this way (where the abstract apply perfectly matches the constructor), you can even get case classes to work without manually defining the abstract apply method in the companion:
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}
Short answer: no straightforward way; try to workaround and resist the desire.
Constructors in Scala are defined in the body of the class and take parameters after the class name e.g.
class A(i: Int) {
println(i)
}
The println(i) in this case is the constructor logic. If you now extend A, like this:
class B(i: Int) extends A(i)
and instantiate B, val b1 = new B(2) you'll see that the constructor is indeed inherited.
As you've already found out, Scala allows you to define alternative constructors by defining functions called this. But these alternative constructors must call the primary constructor.
The way I understand it is that there is really only one constructor for any Scala class, the alternative constructors just filter into it. For example:
class A(x: Int, y: Int) {
// do some constructing!
def this(x: Int) = {
this(x, 1) // provide a default value for y
}
}

Implement a macro in superclass and expand it in subclasses

I want to do something like this:
trait Endo {
def apply[T](x: T): T
}
trait SuperType {
def endoMap(f: Endo): SuperType = macro SuperTypeMacro.endoMapImpl
}
case class Foo(x: Int) extends SuperType {
// endoMapImpl expands to
// Foo(f(x))
}
case class Bar(x: Int, y: Boolean) extends SuperType {
// endoMapImpl expands to
// Bar(f(x), f(y))
}
Ideally the only thing I would need to write is extends SuperType. Is it possible? If not, I believe macro annotations should allow this; am I right?
I think what you're looking for is c.prefix, that contains the receiver of the current macro method call. Once you get hold of it, you can branch on its type.

Scala: what is the purpose of 'override'

I'm not sure what the purpose of override keyword is, in scala. If I have
trait Shape { def foo(v: Int) }
class Triangle extends Shape { override def foo(v: Int) {} }
it behaves (apparently at least) exactly the same as it does without override.
In the case you are implementing an abstract method as in your example, it is not strictly necessary to add the override modifier.
However, in case you want to override a concrete method from the superclass, the override modifier is necessary. This is to avoid accidental overrides which could happen with mixing composition -- mixing-in traits during some refactoring could easily introduce a method definition that could be overridden by the method defined in the body of the class, hence the need for explicitly stating that a method is an override.
In your particular case, you got a comprehensive answer from axel22. I just want to add, that there is at least one more case where you may encounter override modifier. The keyword can also be used with trait methods.
Imagine that you have an abstract class:
abstract class Writer {
def print(str: String)
}
and its concrete implementation that prints on a console
class ConsoleWriter extends Writer {
def print(str: String) = println(str)
}
Now, you want to create a trait that will modify its behaviour. Look at the following implementation:
trait Uppercase extends Writer {
abstract override def print(str: String) =
super.print(str.toUpperCase())
}
Notice that a method has two modifiers: abstract and override. This is only allowed for traits and it means that the trait must be mixed into some class that has a concrete definition of the method in question
With the definition above, you can do:
val writer = new ConsoleWriter with Uppercase
writer.print("abc")
which will yield the result
ABC
Much in the same vain, you can add more traits:
trait WithSpaces extends Writer {
abstract override def print(str: String) =
super.print(str.split("").mkString(" ").tail)
}
Now when you call
val writer = new ConsoleWriter with Uppercase with WithSpaces
writer.print("abc")
you will see:
A B C
The above usage of an override modifier in traits is a distinguishing feature in scala and you won't see it in java.
It's for error checking.
Suppose you have
trait Shape { def foo(v: Int) = 1 }
class Triangle extends Shape { override def foo(v: Int) = 2 }
and then you change Shape to
trait Shape { def bar(v: Int) = 1 }
In that case the "override" will tell you that the foo in Triangle overrides nothing.
See also:
http://docs.oracle.com/javase/7/docs/api/java/lang/Override.html
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final