Scala - Extends multi class with parameters - scala

I would like to make some classes like this.
class A(val a1: String) {
def message() = println(a1)
}
class B(val b1: String) {
def doB() = println(b1)
}
class C(val c1: String) {
def something() = println(c1)
}
class AB(val a: String, val b: String) extends A(a) with B(b) {
// ^error
}
class AC..
class BC..
I tried to use trait but since trait cannot have any parameter, It made error too. How should I do to make somthing like this.

It gives you error because trait doesn't have constructor. But you can change it to the trait parameters like this;
class A(val a1: String) {
def message() = println(a1)
}
trait B {
def b: String
def doB() = println(b)
}
class AB(val a: String, val b: String) extends A(a) with B {
//this should work
}

Related

How to substitute generic anonymous functions?

Suppose there is a trait for legged animals:
trait Legged {
val legs: Int
def updateLegs(legs: Int): Legged
}
And there two such legged animals:
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
case class Dog(name: String, legs: Int = 4) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
There is also a holder for these animal, in a farm
case class Farm(chicken: Chicken, dog: Dog)
And a generic method to mutate all the legged animals by adding them one extra leg
def mutate(legged: Legged): Legged = legged.updateLegs(legged.legs + 1)
The question is how to implement a method on the Farm so that it takes the mutate: Legged => Legged function as a parameter and applies it to all the Legged animals?
val farm = Farm(Chicken(1500), Dog("Max"))
farm.mapAll(mutate) //this should return a farm whose animals have an extra leg
What I've come with thus far, but it doesn't actually work
trait LeggedFunc[T <: Legged] extends (T => T)
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll(leggedFunc: LeggedFunc[Legged]): Farm = {
//todo how to implement?
val c = leggedFunc[Chicken](chicken)
}
}
I know how to do it with patter matching, but that leads to potential MatchError.
A possible way to do that (type-safely, without using asInstanceOf) could be using object-dependant type.
First of all, we should add an abstract member that uses the concrete type of Legged subclasses:
sealed trait Legged { self =>
type Me >: self.type <: Legged // F-Bounded like type, Me have to be the same type of the subclasses
val legs: Int
def updateLegs(legs: Int): Me
}
Then, the Legged subclasses became:
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
type Me = Chicken
override def updateLegs(legs: Int): Chicken = copy(legs = legs)
}
case class Dog(name: String, legs: Int = 4) extends Legged {
type Me = Dog
override def updateLegs(legs: Int): Dog = copy(legs = legs)
}
In this way, it is possible to define a function that returns the concrete subclass of the Legged passed (similar to what #Gaƫl J done):
trait LeggedFunc {
def apply(a : Legged): a.Me
}
val mutate = new LeggedFunc { override def apply(legged: Legged): legged.Me = legged.updateLegs(legged.legs + 1) }
Finally, the Farm class is straightforward defined as:
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll(leggedFunc: LeggedFunc): Farm = {
val c : Chicken = leggedFunc(chicken)
val d : Dog = leggedFunc(dog)
Farm(c, d)
}
}
Scastie for Scala 2
But why object-dependent type?
In Scala 3.0, it is possible to define dependent function type as:
type LeggedFunc = (l: Legged) => l.Me
val mutate: LeggedFunc = (l) => l.updateLegs(l.legs + 1)
Making this solution (object-dependent type) cleaner and type-safe.
Scastie for Scala 3 version
I'll just add to #gianlucaaguzzi's answer that in Scala 2 dependent/polymorphic functions can be emulated with Shapeless
import shapeless.ops.hlist.Mapper
import shapeless.{Generic, HList, Poly1}
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll[L <: HList](mutate: Poly1)(implicit
generic: Generic.Aux[Farm, L],
mapper: Mapper.Aux[mutate.type, L, L]
): Farm = generic.from(mapper(generic.to(this)))
}
object mutate extends Poly1 {
implicit def cse[T <: Legged]: Case.Aux[T, T#Me] =
at(legged => legged.updateLegs(legged.legs + 1))
}
val farm = Farm(Chicken(1500), Dog("Max"))
println(farm.mapAll(mutate)) // Farm(Chicken(1500,3),Dog(Max,5))
This can be done using the method asInstanceOf
trait Legged {
val legs: Int
def updateLegs(legs: Int): Legged
}
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
case class Dog(name: String, legs: Int = 4) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
case class Farm(chicken: Chicken, dog: Dog){
def mapAll(leggedFunc: (Legged) => Legged): Farm = {
copy(
leggedFunc(chicken.asInstanceOf[Legged]).asInstanceOf[Chicken],
leggedFunc(dog.asInstanceOf[Legged]).asInstanceOf[Dog]
)
}
}
def mutate(legged: Legged): Legged = legged.updateLegs(legged.legs + 1)
val farm = Farm(Chicken(1500), Dog("Max"))
println (farm.mapAll(mutate)) // prints: Farm(Chicken(1500,3),Dog(Max,5))
Try it on scastie.
Update: This is an alternative implementation more similar to your own code:
trait LeggedFunc[T <: Legged] extends (T => T)
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll(leggedFunc: LeggedFunc[ Legged]): Farm = {
val c = leggedFunc(chicken).asInstanceOf[Chicken]
val d = leggedFunc(dog).asInstanceOf[Dog]
copy (c, d)
}
}
Try it on scastie.
I think you'd avoid most of the issues you encounter by having a truly generic mutate method (with a type parameter):
def mutate[T <: Legged](legged: T): T = legged.updateLegs(legged.legs + 1)
Then, when applied to a Chicken it will return back a Chicken, and same goes for Dog.

Introduce type constraint for compile time safety

If we have a type class with some ADT as follow
trait MyRule {
type T
class ResourceIdType[A](val value: A)
case class StringResourceIdType(override val value: String) extends ResourceIdType(value)
case class ListResourceIdType(override val value: List[Int]) extends ResourceIdType(value)
def resourceType(rtm: T) : Any
private foo(rtm: T ) = {
resourceType(rtm) match{
case StringResourceIdType(s: String) =>
case ListResourceIdType(l:List[Int]) =>
...
}
type class impls override def resourceType as follow
object FirstClient{
implicit val clientRule = new MyRule{
type T = SomeType
def resourceType(rtm: T) = StringResourceIdType(rtm.name) //assume SomeType has a name property of type String
}
}
object SecondClient{
implicit val clientRule2 = New MyRule{
type T = SomeType2
def resourceType(rtm: T) = ListResourceIdType(rtm.ids) //assume SomeType2 has a ids property of type List[Int]
}
}
Want to make def resourceType(rtm: T) : Any compile time type safe/checked by removing Any and replace with a valid type as T <: ResourceIdType. What would be the right way to address this?
You can add a type parameter in MyRule trait and refine it in each type classes:
trait MyRule {
type T
class ResourceIdType[A](val value: A)
case class StringResourceIdType(override val value: String) extends ResourceIdType(value)
case class ListResourceIdType(override val value: List[Int]) extends ResourceIdType(value)
type F <: ResourceIdType[_]
def resourceType(rtm: T) : F
private def foo(rtm: T): Unit = {
resourceType(rtm) match {
case StringResourceIdType(s: String) =>
case ListResourceIdType(l:List[Int]) =>
}
}
}
object FirstClient{
implicit val clientRule = new MyRule{
case class SomeType(name: String)
type T = SomeType
type F = StringResourceIdType
def resourceType(rtm: T) = StringResourceIdType(rtm.name) //assume SomeType has a name property of type String
}
}
object SecondClient{
implicit val clientRule2 = new MyRule{
case class SomeType2(ids: List[Int])
type T = SomeType2
type F = ListResourceIdType
def resourceType(rtm: T) = ListResourceIdType(rtm.ids) //assume SomeType2 has a ids property of type List[Int]
}
}
The following compiles. Please let me know if it addresses your problem.
package net
trait SomeType {
def name: String
}
trait SomeType2 {
def ids: List[Int]
}
// Introduce an Algebraic Data Type
class ResourceValue
case class StringValue(x: String) extends ResourceValue
case class ListIntsValue(x: List[Int]) extends ResourceValue
trait MyRule {
type T
sealed trait ResourceIdType {
val value: ResourceValue
}
case class StringResourceIdType(override val value: StringValue) extends ResourceIdType
case class ListResourceIdType(override val value: ListIntsValue) extends ResourceIdType
def resourceType(rtm: T): ResourceIdType
private def foo(rtm: T): ResourceValue = {
resourceType(rtm) match {
case StringResourceIdType(s # StringValue(_)) => s
case ListResourceIdType(l # ListIntsValue(_)) => l
}
}
}
object FirstClient{
implicit val clientRule = new MyRule {
type T = SomeType
override def resourceType(rtm: T): ResourceIdType =
StringResourceIdType(StringValue(rtm.name))
}
}
object SecondClient{
implicit val clientRule2 = new MyRule {
type T = SomeType2
override def resourceType(rtm: T): ResourceIdType =
ListResourceIdType(ListIntsValue(rtm.ids))
}
}

Scala constructor signature

Is it possible to define constructor signature in Scala ?
abstract class A {
def this (s: String): this.type // doesn't work
def this (i: Int): this.type // doesn't work
def this (d: Double): this.type // doesn't work
}
class B(var s: String) extends A {
def this(i: Int) = {
this("int "+i.toString())
}
def this(d: Double) = {
this("double "+d.toString())
}
}
What are you trying to achieve? You can do like this:
abstract class A(i: Int)
case class B(s: String) extends A(s.toInt) {
def this(i: Int) = {
this(i.toString)
}
def this(d: Double) = {
this(d.toString)
}
}
Usage:
B("1")
new B(1)
new B(1.0)
You can't do exactly what you want, as pointed out by other answer, but one approach is to use a factory:
trait Foo {
// methods you need
}
trait FooCompanion[T <: Foo] {
// these methods replace constructors in your example
def apply(s: String): T
def apply(i: Int): T
...
}
Implementation:
class Bar(s: String) extends Foo {
...
}
object Bar extends FooCompanion[Bar] {
def apply(s: String) = new Bar(s)
...
}
and you can have methods taking FooCompanion. This pattern is used e.g. in the Scala collections library.
No that is not possible. Constructors are special: You need to write new X() instead of X(), and there is no polymorphic dispatch, e.g. you cannot do def test[A]() = new A(). So there is no scenario in which an abstract constructor would make any sense.

"return this" in a covariant trait that return actual type

This was probably asked before, but I have this problem:
trait Container[+A] {
def a: A
def methodWithSideEffect() = {
// perform some side effecting work
this
}
}
class IntContainer(val a: Int) extends Container[Int]
How do I have the methodWithSideEffect in IntContainer return an IntContainer instead of a Container[Int]? I would also want not to add any parameter to the Container trait, at least from the API user point of view. Note that I did make a workaround with an implicit:
implicit class MyContainer[A <: Container[_]](c: A) {
def methodWithSideEffect(): A = {
// perform work
c
}
}
However, I am quite sure there is some way to do this more elegantly.
You can do this with a self type:
trait Container[+A] { self =>
def a: A
def methodWithSideEffect(): self.type = {
// perform some side effecting work
this
}
}
class IntContainer(val a: Int) extends Container[Int]
...
val x: IntContainer = new IntContainer(42).methodWithSideEffect()
Or simply with this.type:
trait Container[+A] {
def a: A
def methodWithSideEffect(): this.type = {
// perform some side effecting work
this
}
}
class IntContainer(val a: Int) extends Container[Int]

How to call `apply` on a superclass in Scala?

My class inherits from some base class, and implements apply method with exactly the same signature as the base's one. I want to call base's apply method from my class.
When I try following:
class MyClass extends BaseClass {
def apply(k: String, v: String) = {
super.apply(k, v)
...
}
...
}
I got value apply is not a member of BaseClass... compile error.
How should I call base's apply method from the child class?
Also, why it is possible to override apply method without an override keyword?
EDIT: Actual code:
class OAuthParamsBuilder(helper: OAuthParamsHelper)
extends KeyValueHandler {
def apply(k: String, v: String): Unit = {
...
}
}
class OAuthInitSupportBuilder
extends OAuthParamsBuilder(StandardOAuthParamsHelper) {
/*override*/ def apply(k: String, v: String): Unit = {
super.apply(k, v)
...
}
...
}
EDIT: I've noticed that KeyValueHandler is a trait, this may be an issue.
trait KeyValueHandler extends ((String, String) => Unit)
You are not helping us help you, but I suspect this is the true definition of apply on the base class:
def apply(kv: (String, String)) = ???
EDIT
The code you pasted is not enough, as the problem is not reproducible with it:
trait OAuthParamsHelper
trait KeyValueHandler
class OAuthParamsBuilder(helper: OAuthParamsHelper) extends KeyValueHandler {
def apply(k: String, v: String): Unit = ???
}
object StandardOAuthParamsHelper extends OAuthParamsHelper
class OAuthInitSupportBuilder extends OAuthParamsBuilder(StandardOAuthParamsHelper) {
override def apply(k: String, v: String): Unit = {
super.apply(k, v)
???
}
}