Issue with trait and case class inheritance: scala - scala

Below code gives me the error
Method 'someMethod' overrides nothing
But isn't case class C extending trait A? Why am I getting this error
trait A
trait B {
def someMethod(req: A): Unit
}
case class C(i: Int, j: Int) extends A
object D extends B {
override def someMethod(req: C) ={
//some implementation
}
}

The problem is that you can pass any value of type A to this method:
def someMethod(req: A)
But you can only pass values of type C to this method:
override def someMethod(req: C)
So the second version is not a full implementation of the first because it can't handle values of type A which are not values of type C. So the second version cannot override the first.
Possible solution:
override def someMethod(req: A) =
req match {
case C(i, j) => // Code
case _ => // Error handling
}

Alternative to Tim's answer, maybe you want something like this:
trait A
final case class C(i: Int, j: Int) extends A
trait B[T <: A] {
def someMethod(req: T): Unit
}
object D extends B[C] {
override def someMethod(req: C): Unit = {
//some implementation
}
}

Related

Specify concrete type for methods in Scala trait

I want to define a method in a Scala trait where both a parameter to the method and the return type correspond to the same concrete class which extends the trait. I've tried something like the following:
trait A {
def foo(obj: this.type): this.type
}
final case class B(val bar: Int) extends A {
override def foo(obj: B): B = {
B(obj.bar + this.bar)
}
}
object Main {
def main(args: Array[String]) = {
val b1 = new B(0)
val b2 = new B(0)
val b3: B = b1.foo(b2)
}
}
However, trying to compile this code gives the following error:
Test.scala:5: error: class B needs to be abstract. Missing implementation for:
def foo(obj: B.this.type): B.this.type // inherited from trait A
case class B(val bar: Int) extends A {
^
Test.scala:6: error: method foo overrides nothing.
Note: the super classes of class B contain the following, non final members named foo:
def foo: ((obj: _1.type): _1.type) forSome { val _1: B }
override def foo(obj: B): B = {
^
2 errors
There's obviously something I'm misunderstanding about the Scala type system here. The signature of foo in class B is what I want it to be, but I don't know how to correctly define the method in A (or if this is even possible). It seems like this question is asking something quite similar, but I don't immediately see how the answer applies in my situation.
The type annotation this.type means that you may only return this. So in that case you may not return another instance of B, the same holds for the method parameter.
If this was just about the return type, a solution would be to require foo to return something of type A, the override method in B can specialize the return type to return B.
However since you also have an argument which you want to be of the type of the subtype you could use a Self Recursive Type. The following example compiles and should do what you want.
trait A[S <: A[S]] {
def foo(obj: S): S
}
case class B(val bar: Int) extends A[B] {
override def foo(obj: B): B = {
B(obj.bar + 1)
}
}
Consider type class solution
case class B(bar: Int)
// type class
trait Fooable[A] {
def foo(x: A, y: A): A
}
// proof that B satisfies Fooable constraints
implicit val fooableB: Fooable[B] = new Fooable[B] {
override def foo(x: B, y: B): B = B(x.bar + y.bar)
}
// a bit of syntax sugar to enable x foo y
implicit class FooableOps[A](x: A) {
def foo(y: A)(implicit ev: Fooable[A]) = ev.foo(x,y)
}
val b1 = B(1)
val b2 = B(41)
b1.foo(b2)
// B(42)
which Scala 3 simplifies to
case class B(bar: Int)
// type class
trait Fooable[A] {
extension (x: A) def foo (y: A): A
}
// proof that B satisfies Fooable constraints + syntactic sugar
given Fooable[B] with
extension (x: B) def foo (y: B): B = B(x.bar + y.bar)
val b1 = B(1)
val b2 = B(41)
b1.foo(b2)
// B(42)
See Scala FAQ: How can a method in a superclass return a value of the “current” type?

How can I create a new specific type of class when extending a trait in scala

I have a trait in which (among other things) I want a method that will create a new instance of the class, and then there are other methods that use that instance of the class.
A very cut down version of my code is:
trait A {
def prev: A
def get(end: A): A
}
class B extends A {
def prev: B = new B()
def get(end: B): B = end.prev
}
What I am trying to show here is that next will return a new instance of the class (in reality with some new constructor parameters) and that the get method will make use of next internally (along with other logic)
The problem with the above is that the compiler says "class B must implement abstract member get(end: A): A", which is reasonable.
I tried to solve it using type bounds as:
trait A {
def prev: A
def get(end: A): A
}
case class B extends A {
def prev[TX <: A]: TX = new B()
def get[TX <: A](end: TX): TX = end.prev
}
but now the error is "Expression of type B doesn't conform to expected type TX" on new B() and "Expression of type A doesn't conform to expected type TX" on end.prev
I don't understand why this is a problem as next is returning a B which is a subtype of A, which is what TX is.
Is there a way to implement what I wish to do here?
A bit of context in case the above all seems too abstract. I am implementing a circular doubly linked list as there's nothing like that that I could find. The trait includes:
trait Circular[T] {
// Nodes in the list from the current position up to but NOT INCLUDING the end
def toStream(end: Circular[T]): Stream[Circular[T]]
def prev: Circular[T]
...
And my class looks like:
case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
case class CircularList[T](first: Node[T], last: Node[T], current: Node[T])
extends Circular[T] {
// Nodes in the list from the current position up to but not including the end
def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
#tailrec
def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
if (this == end) {
acc
} else {
toStreamRec(end.prev, Stream.cons(end.prev, acc))
}
}
toStreamRec(end, Stream.empty)
}
def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
...
so toStream maps to get in my cutdown example.
What you want is something called F-bound generic. The code goes like this:
trait Base[T <: Base[T]] {
def next: T
def get(end: T): T
}
class Chlid extends Base[Child] {
def next: Chlid = new Chlid()
def get(end: Chlid): Chlid = end.next
}
Your code doesn't compile because
def get(end: B): B
is not an override of
def get(end: A): A
because the original method accepts objects of type A while your method requires only more narrow type B
For your Circular example you want something like
trait Circular[T, C <: Circular[T, C]] {
// Nodes in the list from the current position up to but NOT INCLUDING the end
def toStream(end: C): Stream[C]
def next: C
}
case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
case class CircularList[T](first: Node[T], last: Node[T], current: Node[T]) extends Circular[T, CircularList[T]] {
// Nodes in the list from the current position up to but not including the end
def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
#tailrec
def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
if (this == end) {
acc
} else {
toStreamRec(end.prev, Stream.cons(end.prev, acc))
}
}
toStreamRec(end, Stream.empty)
}
def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
override def next: CircularList[T] = ???
}

Abstract type, variables and typeclasses in Scala

I'm trying to make a typeclass that depends on user input. Imagine we have some case objects:
sealed trait H
case object Ha extends H
case object Hb extends H
and the type class:
trait Foo[A] {
def bar: String
}
object Foo {
def bar[A : Foo] = implicitly[Foo[A]].bar
implicit object FooA extends Foo[Ha.type] {
override def bar: String = "A"
}
implicit object FooB extends Foo[Hb.type] {
override def bar: String = "B"
}
}
While I found a working solution using a match:
variableComingFromMainArgs match {
case "a" => Foo.bar[Ha.type] _
case "b" => Foo.bar[Hb.type] _
}
I remember that we have abstract types in Scala, so I could change my case class into:
sealed trait H {
type T <: H
}
case object Ha extends H {
type T = this.type
}
case object Hb extends H {
type T = this.type
}
Now, when depending on user input to the program, I could do something like
val variable = Ha
println(Foo.bar[variable.T])
However, for some reason this doesn't work the and the error is not very useful for me:
error: could not find implicit value for evidence parameter of type Foo[variable.T]
println(Foo.bar[variable.T])
Any ideas if this can be overcome, if not, why?
Thanks.
Implicits are compile time constructs so in principle they cannot depend on user input directly (programmer can wire it for example with pattern matching as you did).
Consider the following code. It compiles and works as intended:
trait H {
type A
}
case object Ha extends H {
override type A = Int
}
case object Hb extends H {
override type A = Long
}
trait Adder[T] {
def add(a: T, b: T): T
}
implicit object IntAdder extends Adder[Int] {
override def add(a: Int, b: Int): Int = a + b
}
implicit object LongAdder extends Adder[Long] {
override def add(a: Long, b: Long): Long = a + b
}
def addWithAdder(input: H)(a: input.A, b: input.A)(implicit ev: Adder[input.A]): input.A = ev.add(a, b)
val x: Int = addWithAdder(Ha)(3, 4)
val y: Long = addWithAdder(Hb)(3, 4)
Let's focus on addWithAdder method. Thanks to path dependent types compiler can choose correct implicit for this task. But still this method is basically the same as the following:
def add[T](a: T, b: T)(implicit ev: Adder[T]) = ev.add(a, b)
The only advantage first one can have is that you can provide all instances yourself and stop the user of your code to add own types (when H is sealed and all implementations are final).

Type Parameter in Case Class Using Trait w/ Implicits

Let's say we have a trait:
trait ThingToThing[-A, +B] { def apply(a: A): B }
and its companion object:
object ThingToThing {
implicit object StringToBoolean extends ThingToThing[String, Boolean] {
override def apply(a: String): Boolean = a.toBoolean
}
}
and a case class:
case class Thing[A](a: A) {
def to[B](implicit thing: ThingToThing[A, B]): B = thing(a)
}
This allows me to do the following:
Thing("true").to[Boolean]
res0: Boolean = true
This is all fine and dandy, and I can do something like:
case class MyClass(ss: Seq[String]) {
def doStuff(s: String) = Thing(s).to[Boolean]
}
But what I'd like to do, however, is something like:
case class MyClass[B](ss: Seq[String]) {
def doStuff(s: String) = Thing(s).to[B]
}
But, this errors with:
error: could not find implicit value for parameter thing: ThingToThing[String,B]
Is there a way I can use a type parameter in my MyClass?
** Don't get caught up on the toy example of converting a String to a Boolean; I just used this as a simple example to illustrate the problem.
The compiler couldn't find an implicit instance of ThingToThing[String,B] (B is unknown) in the call site Thing(s).to[B]:
case class MyClass[B](ss: Seq[String]) {
def doStuff(s: String) = Thing(s).to[B]
}
thus the error.
You can declare the required implicit in the constructor to have it resolved in the call site of object creation (when B is known):
case class MyClass[B](ss: Seq[String])(implicit t2t: ThingToThing[String, B]) {
def doStuff(s: String) = Thing(s).to[B]
}
, or declare it in the method to have it resolved in the call site of the method invocation (when B is known):
case class MyClass[B](ss: Seq[String]) {
def doStuff(s: String)(implicit t2t: ThingToThing[String, B]) = Thing(s).to[B]
}

List of elements implementing typeclass A and B in Scala

I got the following issue when trying to use typeclasses throughout my project.
trait FooAble[T] { def fa(t: T): List[T] }
object Foo { def apply[T](t: T) = implicitly[FooAble[T]].fa(t) }
trait BarAble[T] { def fb(t: T): Double }
object Bar { def apply[T](t: T) = implicitly[BarAble[T]].fb(t) }
And would like to be able to do the following:
// xs contains elements of type A and B which are subclasses of the trait Something
def f(xs: List[Something]) = {
val something = xs.map(Foo)
val somethingElse = xs.map(Bar)
}
However, this would not work as we don't know if Something implements A[]and B[], no implicit implementation found. What do I need to do so that the elements of the list xs implement the typeclasses FooAble and BarAble?
I think this question: What are type classes in Scala useful for? will help you to understand the proper use (& usefulness) of type classes.
Am just extending the answer by Kevin Wright in the above link for your use case (if I understand your need correctly!):
trait Addable[T] {
def zero: T
def append(a: T, b: T): T
}
trait Productable[T] {
def zero: T
def product(a: T, b: T): T
}
implicit object IntIsAddable extends Addable[Int] {
def zero = 0
def append(a: Int, b: Int) = a + b
}
implicit object IntIsProductable extends Productable[Int] {
def zero = 1
def product(a: Int, b: Int) = a*b
}
def sumAndProduct[T](xs: List[T])(implicit addable: Addable[T], productable: Productable[T]) =
(xs.foldLeft(addable.zero)(addable.append), xs.foldLeft(productable.zero)(productable.product))
So akin to above, in your use case, you need to provide implicit objects which implement your type classes FooAble & BarAble and your method signature for function f becomes:
def f[Something](xs: List[Something])(implicit fooable: FooAble[Something], barable: BarAble[Something])