Polymorphism when one argument is not always used - scala

In order to explain the problem I've simplified my code.
Regarding the following classes and object:
abstract class AbstractFoo {
def func: (A, B) => Unit = Bar1.func
}
class ConcreteFoo extends AbstractFoo {
override def func: (A, B) => Unit = Bar2.func
}
object Bar1{
def func(a: A, b: B): Unit = {
println(a.toString)
println(b.toString)
}
}
object Bar2{
def func(a: A, b: B): Unit = {
println(b.toString)
}
}
What I don't like is that Bar2.func accepts an A although it doesn't use it. I want to change the code so Bar2 will look like this:
object Bar2{
def func(b: B): Unit = {
println(b.toString)
}
}

No problem. Change Bar to
object Bar2{
def func(b: B): Unit = {
println(b.toString)
}
}
as you wanted and update ConcreteFoo correspondingly
class ConcreteFoo extends AbstractFoo {
override def func: (A, B) => Unit = (_, b) => Bar2.func(b)
}

Change of signature creates a different method with a different bytecode signature which could override implement different method in some superclass, etc.
Depending on use case you can use method overloading or default arguments or - in your case - ignore one parameter during application:
class ConcreteFoo extends AbstractFoo {
override def func: (A, B) => Unit = (_, b) => Bar2.func(b)
}

Related

Issue with trait and case class inheritance: 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
}
}

How to make implicits available to inner function

I would like to define implicit value in a wrapper function and make it available to inner function, so far I managed to do that by passing implicit variable from wrapper:
case class B()
trait Helper {
def withImplicit[A]()(block: => A): A = {
implicit val b: B = B()
block
}
}
class Test extends Helper {
def useImplicit()(implicit b: B): Unit = {...}
def test = {
withImplicit() { implicit b: B =>
useImplicit()
}
}
}
Is it possible to avoid implicit b: B => and make implicit val b: B = B() available to inner function block?
This will be possible in Scala 3 with implicit function types (keyword given is instead of implicit)
case class B()
trait Helper {
def withImplicit[A]()(block: (given B) => A): A = {
given B = B()
block
}
}
class Test extends Helper {
def useImplicit()(given b: B): Unit = {}
def test = {
withImplicit() {
useImplicit()
}
}
}
https://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html
https://dotty.epfl.ch/blog/2016/12/05/implicit-function-types.html

Scala type class to extend generic type: No implicits found for parameter

I want to write a type class, to add some behavior to a generic type. However, I cannot figure out how to do it; I keep running into the error below.
Imagine you have a generic type MyList[A]:
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
Now you want to add some behavior to this class, e.g. to convert it into a Stream[A]. A type class based extension would seem appropriate:
// inspired by https://scalac.io/typeclasses-in-scala
trait MyListExt[T, A <: MyList[T]] {
def stream(a: A): Stream[T]
}
object MyListExt {
def apply[T, A <: MyList[T]](implicit a: MyListExt[T, A]): MyListExt[T, A] = a
object ops {
implicit class MyListExtOps[T, A <: MyList[T]](val a: A) extends AnyVal {
def stream(implicit ext: MyListExt[T, A]): Stream[T] = ext.stream(a)
}
}
private type T0
implicit val myListToStreamImpl: MyListExt[T0, MyList[T0]] = new MyListExt[T0, MyList[T0]] {
override def stream(a: MyList[T0]): Stream[T0] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
When I now try to use this type class in my code, I get the following error at l.stream:
No implicits found for parameter ext: MyListExt[T_, MyList[Int]]
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
What am I doing wrong, or how can I get my l.stream to work?
I have seen many examples involving type classes and implicit conversion, but none so far operating on generic types.
implicit def myListToStreamImpl[T]: MyListExt[T, MyList[T]] = new MyListExt[T, MyList[T]] {
override def stream(a: MyList[T]): Stream[T] = {
def fold(l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty[T1])
}
}
Your types don't align because you've used that private type for whatever bizarre reason. Types nested inside objects have a completely different application, and they don't relate to your current use case.
The trouble is that in l.stream.foreach(println) the l is implicitly transformed to new MyListExt.ops.MyListExtOps[.., ..](l) and generics are inferred to be [Nothing, MyList[Int]], which doesn't satisfy [T, A <: MyList[T]].
I can't see reason to parametrize MyListExt with both T and A <: MyList[T]. I guess T is enough, use MyList[T] instead of A.
Don't use private type T0, just parametrize myListToStreamImpl (make it def) with T0 aka T.
Try
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
trait MyListExt[T] {
def stream(a: MyList[T]): Stream[T]
}
object MyListExt {
def apply[T](implicit a: MyListExt[T]): MyListExt[T] = a
object ops {
implicit class MyListExtOps[T](val a: MyList[T]) extends AnyVal {
def stream(implicit ext: MyListExt[T]): Stream[T] = ext.stream(a)
}
}
implicit def myListToStreamImpl[T]: MyListExt[T] = new MyListExt[T] {
override def stream(a: MyList[T]): Stream[T] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}

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] = ???
}

How to handle frontier between typeclass and inheritance usage

I am getting frustrated because I don't know how to handle the frontier between my typesafe code and the external API which uses polymorphism and inheritance.
My flow is the following. I receive an entry value of class Class1, which I use to retrieve from an external service an item of Class Class2. Then I need to subtype on both to obtain the runtime type of them and resolve the implicit. However, this is not possible because of type erasure.
trait Typeclass1[A, B] {
def hash(a: A, b: B): String
}
trait Typeclass2[A, B] {
def hash(a: A, b: B): B
}
trait Entity
trait MyEntity1
trait MyEntity2
object db {
def load(any:Any):Entity = new Entity{}
}
class MyClass[T](t: T, a: String) {
def apply(timeout: Long): T = {
val loadFromDB = db.load(t)
loadFromDB match {
case myEntity1: MyEntity1 => applyTypeSafe(myEntity1)
case myEntity2: MyEntity2 => applyTypeSafe(myEntity2)
}
}
def applyTypeSafe[C](c: C)(implicit typeClass1: Typeclass1[C, T], typeclass2: Typeclass2[C, T]): (String, T) = {
typeClass1.hash(c, t) -> typeclass2.hash(c, t)
}
}
I am wondering what is the right pattern to develop this frontier layer. I would probably need a type-constructor for my typeclass to provide at at the constructor of MyClass... or maybe to totally rethinkg my design?
There is no compilation issue if you add implicit definitions in scope for MyEntity and MyEntity2. For example, the code below compiles ok:
trait Typeclass1[A, B] { def hash(a: A, b: B): String }
trait Typeclass2[A, B] { def hash(a: A, b: B): B }
trait Entity
trait MyEntity1 extends Entity
trait MyEntity2 extends Entity
object db { def load(any:Any):Entity = new Entity {} }
implicit def MyEntity1HasTypeclass1[T] = new Typeclass1[MyEntity1, T] {
def hash(a: MyEntity1, t: T) = a.toString
}
implicit def MyEntity1HasTypeclass2[T] = new Typeclass2[MyEntity1, T] {
def hash(a: MyEntity1, t: T) =t
}
class MyClass[T](t: T, a: String) {
def apply(timeout: Long): (String, T) = {
db.load(t) match {
case myEntity1: MyEntity1 => applyTypeSafe(myEntity1)
}
}
def applyTypeSafe[C](c: C)(implicit typeClass1: Typeclass1[C, T],
typeclass2: Typeclass2[C, T]): (String, T) = {
typeClass1.hash(c, t) -> typeclass2.hash(c, t)
}
}