How to make implicits available to inner function - scala

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

Related

Polymorphism when one argument is not always used

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)
}

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

Scala generic functions

I have an abstract class
abstract class Foo {
def foo(a: Int): Int
...
}
// Usage
new Foo {
def foo(a: Int) = {
println("Foo")
a
}
}
I frequently see a companion object to make this a little less verbose for callers (e.g. the Play framework).
object Foo {
def apply(f: Int => Int) = new Foo {
def foo(a: Int) = f(a)
}
}
// Usage
Foo { a =>
println("Foo")
a
}
But suppose I make the method generic
abstract class Foo {
def foo(a: T): T
...
}
// Usage
new Foo {
def foo(a: T) = {
println("Foo")
a
}
}
Can I still use a companion object, i.e. can I apply generic type parameters to a function, rather than a method or class?
Yes you can do this by emulating rank 2 polymorphism. Based on this article you can do:
trait ~>[F[_],G[_]] {
def apply[A](a: F[A]): G[A]
}
type Id[A] = A
abstract class Foo {
def foo[T](a: T): T
}
object Foo {
def apply(f: Id ~> Id) = new Foo {
def foo[T](a: T): T = f(a)
}
}
val fun = new (Id ~> Id) { def apply[T](a: T): T = { println("Foo"); a } }
val foo = Foo(fun)
foo.foo(1)
foo.foo("String")

Working around overloading restriction (implementing a trait for several types)

I know it's not possible to overload methods which differ only in the return type. But I wonder if there are any smart strategies to deal efficiently with this situation:
trait Reader[A] { def read(in: java.io.DataInput): A }
trait B; trait C
def doSomethingB()(implicit r: Reader[B]) = ()
def doSomethingC()(implicit r: Reader[C]) = ()
trait MultiReader extends Reader[B] with Reader[C] { // not possible
implicit me = this
doSomethingB()
doSomethingC()
}
By smart and efficient I mean, I would like to avoid clutter and unnecessary inner class generations like this:
trait MultiReader {
implicit object RB extends Reader[B] { ... }
implicit object RC extends Reader[C] { ... }
doSomethingB()
doSomethingC()
}
EDIT
Here is a partial solution. I have been re-reading this gist by Miles Sabin in the last days which appeared very inspiring. So I can do the following:
type Tagged[U] = { type Tag = U }
type ##[T, U] = T with Tagged[U]
trait Reader[A] { def read(in: java.io.DataInput ## A): A }
And then this works:
trait MultiReader {
def read(in: java.io.DataInput ## B): B
def read(in: java.io.DataInput ## C): C
}
But the inheritance is somewhat still broken:
trait MultiReader extends Reader[B] with Reader[C]
(fails with "self-type MultiReader does not conform to Reader[B]'s selftype Reader[B]").
This still instantiates a Function1 plus an anonymous Reader for each type parameter required, but at least it is syntactically more concise:
object Reader {
implicit def fromFun[A](implicit fun: java.io.DataInput => A): Reader[A] =
new Reader[A] { def read(in: java.io.DataInput): A = fun(in) }
}
trait Reader[A] { def read(in: java.io.DataInput): A }
def doSomethingB()(implicit r: Reader[B]): Unit = println(r.read(null))
def doSomethingC()(implicit r: Reader[C]): Unit = println(r.read(null))
trait MultiReader {
implicit def readB(in: java.io.DataInput): B = new B { override def toString = "B" }
implicit def readC(in: java.io.DataInput): C = new C { override def toString = "C" }
doSomethingB()
doSomethingC()
}
new MultiReader {} // --> B, C
The main problem seems to be that Scala doesn't allow one to implement a generic trait more than once, even if the type parameters differ. Interestingly, although calling into the tagged version works correctly (I can deliberately call read with the input tagged B or C), it fails when using structural types, like this:
def doSomethingB()(implicit r: { def read(in: java.io.DataInput ## B): B }) = ()
def doSomethingC()(implicit r: { def read(in: java.io.DataInput ## C): C }) = ()
There is a dispatch bug here, and both will call into reading C.
If there is a constraint that B and C are within one class hierarchy, an idea is to use bounds:
sealed trait B; trait C extends B
trait UpDownReader[Up, Down] {
def read[A >: Down <: Up : Manifest](in: java.io.DataInput): A
}
class MultiReader(implicit mfx: Manifest[X], mfy: Manifest[Y])
extends UpDownReader[X, Y] {
def read[A >: Y <: X](in: java.io.DataInput)(implicit mf: Manifest[A]): A =
(if (mf == mfx) new X {} else new Y {}).asInstanceOf[A]
}
This works:
val m = new MultiReader
m.read[B](null)
m.read[C](null)
However, I would call this neither elegant nor efficient, given the 'dynamic' comparison of the manifests and then the ugly cast to A.

define method to return type of class extending it

I'd like to be able to do something like this:
trait A {
def f(): ???_THE_EXTENDING CLASS
}
class C extends A {
def f() = self
}
class D extends A {
def f() = new D
}
class Z extends D {
def f() = new Z
}
And the following would not compile, given the above code
class Bad1 extends A {
def f() = "unrelated string"
}
class Bad2 extends A {
def f() = new C // this means that you can't just define a type parameter on
// A like A[T <: A] with f() defined as f: T
}
class Bad3 extends D // f() now doesn't return the correct type
Is there a name for this kind of relationship? And how is it annotated/implemented in Scala?
Edit
The following sort of works, as you can see:
scala> trait A {
| def f: this.type
| }
defined trait A
scala> class C extends A {
| def f = this
| }
defined class C
scala> class D extends A {
| def f = new D
| }
<console>:7: error: type mismatch;
found : D
required: D.this.type
def f = new D
^
Is there a way to get around that?
Edit 2
Using the second system, I can do this, which is good up to the definition of class D:
scala> trait A[T <: A[T]] { def f(): T }
defined trait A
// OR
scala> trait A[T <: A[T]] { self: T =>
| def f(): T
| }
scala> class C extends A[C] { def f() = new C }
defined class C
scala> class D extends C
defined class D
scala> (new D).f
res0: C = C#465fadce
I'm afraid there is no possibility to know what is the extended class from the extending class.
The closest to what you'd like to have is something similar to Curiously Recurring Template Pattern (CRTP) well known from C++.
trait A[T <: A[T]] {
def f(): T;
}
class C extends A[C] {
def f() = new C
}
class D extends A[D] {
def f() = new D
}
One thing that you can do, is to return type this.type:
trait A {
def f(): this.type
}
class C extends A {
def f() = this
}
class D extends A {
def f() = this
}
class Z extends D {
override def f() = this
def x = "x"
}
println((new Z).f().x)
This can be useful for builders.
Here is another possible solution. It's combination of self type + type parameter:
trait A[T <: A[T]] { self: T =>
def f(): T
}
class Z extends A[Z] {
override def f() = new Z
def x = "x"
}
println((new Z).f().x)
Here you can find more info about this solution:
scala self-type: value is not a member error