Single Abstract Method Equivalent to a Trait? - scala

Consider this trait:
trait Foo {
def m1(id : Int) : Try[String]
}
And an instance of this:
val g : Foo = new Foo {
override def m1(id: Int): Try[String] = Success("Good job")
}
Intellij offered a suggestion that this could converted to a Single Abstract Method:
val g : Foo = (id: Int) => Success("Good job")
Are these two equivalent and how?

Lets check what the scalac do for:
import scala.util.{Success, Try}
trait Foo {
def m1(id : Int) : Try[String]
}
object MainClass {
val g : Foo = new Foo {
override def m1(id: Int): Try[String] = Success("Good job")
}
}
run:
$ scalac -print src/main/scala/MainClass.scala
and output:
[[syntax trees at end of cleanup]] // MainClass.scala
package <empty> {
abstract trait Foo extends Object {
def m1(id: Int): scala.util.Try
};
object MainClass extends Object {
private[this] val g: Foo = _;
<stable> <accessor> def g(): Foo = MainClass.this.g;
def <init>(): MainClass.type = {
MainClass.super.<init>();
MainClass.this.g = {
new <$anon: Foo>()
};
()
}
};
final class anon$1 extends Object with Foo {
override def m1(id: Int): scala.util.Try = new scala.util.Success("Good job");
def <init>(): <$anon: Foo> = {
anon$1.super.<init>();
()
}
}
}
And do the same steps for:
import scala.util.{Success, Try}
trait Foo {
def m1(id : Int) : Try[String]
}
object MainClass {
def main(args: Array[String]): Unit = {
val g : Foo = (id: Int) => Success("Good job")
}
}
run:
$ scalac -print src/main/scala/MainClass.scala
output:
[[syntax trees at end of cleanup]] // MainClass.scala
package <empty> {
abstract trait Foo extends Object {
def m1(id: Int): scala.util.Try
};
object MainClass extends Object {
private[this] val g: Foo = _;
<stable> <accessor> def g(): Foo = MainClass.this.g;
final <artifact> private[this] def $anonfun$g$1(id: Int): scala.util.Try = new scala.util.Success("Good job");
def <init>(): MainClass.type = {
MainClass.super.<init>();
MainClass.this.g = {
((id: Int) => MainClass.this.$anonfun$g$1(id))
};
()
}
}
}
As you can see they are not the same for compiler.
In the first case, it is an anonymous object in second it is an anonymous function.

Related

Finding the second matching implicit

Consider the following setup:
trait Foo[A]
object Foo extends Priority2
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {}
}
Now, in a REPL (having loaded the above code up), I can do the following:
scala> def implicitlyFoo[A](implicit foo: Foo[A]) = foo
implicitlyFoo: [A](implicit foo: Foo[A])Foo[A]
scala> implicitlyFoo
res1: Foo[Double] = Priority2$$anon$3#79703b86
Is there a way to encode with some typelevel magic that I want to skip over the instances with A =:= Double, but still let type inference figure out what A is?
I do not want to shadow foo3. This is an MVCE: in my real case, foo3 is a def with other implicit arguments (and may play an indirect role in deriving other Foo's).
I've tried =:!= from shapeless but to no avail:
scala> import shapeless._
import shapeless._
scala> def implicitlyFoo2[A](implicit foo: Foo[A], ev: A =:!= Double) = foo
implicitlyFoo2: [A](implicit foo: Foo[A], implicit ev: A =:!= Double)Foo[A]
scala> implicitlyFoo2
<console>:16: error: ambiguous implicit values:
both method neqAmbig1 in package shapeless of type [A]=> A =:!= A
and method neqAmbig2 in package shapeless of type [A]=> A =:!= A
match expected type Double =:!= Double
implicitlyFoo2
^
Dirty hack is to downcast macro context to its implemenation and use compiler internals.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait Foo[A] {
def say: String
}
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {
override def say: String = "int"
}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {
override def say: String = "bool"
}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {
override def say: String = "double"
}
}
object Foo extends Priority2
def materializeSecondFoo[A]: Foo[A] = macro impl
def impl(c: whitebox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[reflect.macros.runtime.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
var infos = List[analyzer.ImplicitInfo]()
new analyzer.ImplicitSearch(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = typeOf[Foo[_]].asInstanceOf[global.Type],
isView = false,
context0 = global.typer.context.makeImplicit(reportAmbiguousErrors = false),
pos0 = c.enclosingPosition.asInstanceOf[global.Position]
) {
override def searchImplicit(
implicitInfoss: List[List[analyzer.ImplicitInfo]],
isLocalToCallsite: Boolean
): analyzer.SearchResult = {
val implicitInfos = implicitInfoss.flatten
if (implicitInfos.nonEmpty) {
infos = implicitInfos
}
super.searchImplicit(implicitInfoss, isLocalToCallsite)
}
}.bestImplicit
val secondBest = infos.tail.head
global.gen.mkAttributedRef(secondBest.pre, secondBest.sym).asInstanceOf[Tree]
}
materializeSecondFoo.say // bool
Tested in 2.12.8. Motivated by shapeless.Cached.
In 2.13.0 materializeSecondFoo.say should be replaced with
val m = materializeSecondFoo
m.say
The latter is still working in 2.13.10.
Scala 3 implementation:
import scala.quoted.{Quotes, Type, Expr, quotes}
import dotty.tools.dotc.typer.{Implicits => dottyImplicits}
transparent inline def materializeSecondFoo: Foo[_] = ${impl}
def impl(using Quotes): Expr[Foo[_]] = {
import quotes.reflect.*
given c: dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val typer = c.typer
val search = new typer.ImplicitSearch(
TypeRepr.of[Foo[_]].asInstanceOf[dotty.tools.dotc.core.Types.Type],
dotty.tools.dotc.ast.tpd.EmptyTree,
Position.ofMacroExpansion.asInstanceOf[dotty.tools.dotc.util.SourcePosition].span
)
def eligible(contextual: Boolean): List[dottyImplicits.Candidate] =
if contextual then
if c.gadt.isNarrowing then
dotty.tools.dotc.core.Contexts.withoutMode(dotty.tools.dotc.core.Mode.ImplicitsEnabled) {
c.implicits.uncachedEligible(search.wildProto)
}
else c.implicits.eligible(search.wildProto)
else search.implicitScope(search.wildProto).eligible
def implicits(contextual: Boolean): List[dottyImplicits.SearchResult] =
eligible(contextual).map(search.tryImplicit(_, contextual))
val contextualImplicits = implicits(true)
val nonContextualImplicits = implicits(false)
val contextualSymbols = contextualImplicits.map(_.tree.symbol)
val filteredNonContextual = nonContextualImplicits.filterNot(sr => contextualSymbols.contains(sr.tree.symbol))
val successes = (contextualImplicits ++ filteredNonContextual).collect {
case success: dottyImplicits.SearchSuccess => success.tree.asInstanceOf[ImplicitSearchSuccess].tree
}
successes.tail.head.asExprOf[Foo[_]]
}
materializeSecondFoo.say // bool
val foo = materializeSecondFoo
foo: Foo[Boolean] // compiles
Scala 3.2.0.

Scala : Method overloading and type inference

I cannot understand why Scala is not able to infer an overloaded method's arguments :
object A {
implicit object SequenceMarker
implicit object IntMarker
def b(f: Int => Seq[Int])(implicit ev: SequenceMarker.type) = 0
def b(f: Int => Int)(implicit ev: IntMarker.type) = 0
def c() = { b(i => i + 1) } // this doesn't compile
}
When I try to compile this, I get the following error :
error: missing parameter type
def c() = { b(i => i + 1) }
I've made some investigation using javap and scala -print and figure out that the previous code cannot be compiled without specifying what i is :
object A {
...
def c() = { b((i: Int) => i + 1) }
}
Why is that so ? Is there any other way to overload a method while not specifying its argument's type during the call ?
Thank you in advance.
UPDATE
I've noticed using scala -print :
#SerialVersionUID(value = 0) final <synthetic> class anonfun$c$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
final def apply(i: Int): Int = anonfun$c$1.this.apply$mcII$sp(i);
<specialized> def apply$mcII$sp(i: Int): Int = i.+(1);
final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)));
def <init>(): <$anon: Function1> = {
anonfun$c$1.super.<init>();
()
}
}
that the argument seems to be casted in some way:
scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)))
This line changes depending on the argument's type :
scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)));
...
scala.Int.box(anonfun$c$1.this.apply(v1.$asInstanceOf[String]()))
which would explain why the type is required. Here is the whole log :
package <empty> {
object A extends Object {
def b(f: Function1, ev: A$SequenceMarker.type): Int = 0;
def b(f: Function1, ev: A$IntMarker.type): Int = 0;
def c(): Int = A.this.b({
(new <$anon: Function1>(): Function1)
}, A$IntMarker);
def <init>(): A.type = {
A.super.<init>();
()
}
};
object A$SequenceMarker extends Object {
def <init>(): A$SequenceMarker.type = {
A$SequenceMarker.super.<init>();
()
}
};
object A$IntMarker extends Object {
def <init>(): A$IntMarker.type = {
A$IntMarker.super.<init>();
()
}
};
#SerialVersionUID(value = 0) final <synthetic> class anonfun$c$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
final def apply(i: Int): Int = anonfun$c$1.this.apply$mcII$sp(i);
<specialized> def apply$mcII$sp(i: Int): Int = i.+(1);
final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)));
def <init>(): <$anon: Function1> = {
anonfun$c$1.super.<init>();
()
}
}
}
Therefore, what I want to achieve cannot be done in the way previously described. Any other idea ?
UPDATE 2
I've also tried :
def c() = { b(_ + 1) }
but I get another error
error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
def c() = { b(_ + 1) }
When I comment the first b(f: Int => Seq[Int]), it compiles well.
It's because for purposes of overload resolution, arguments are typed without an expected type, so there is no information about what function is expected.
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#overloading-resolution
The compiler doesn't care that the set of possible overloads includes only methods that take an Int.

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

stack overflow on overriding lazy val in scala

I have trimmed my code down to the following. I am confused why I am getting a stack overflow between the two filter methods (one in my trait and one in my superclass)
object TestingOutTraits {
val TestHandler = new Object with MySuper with MyTrait {
override lazy val createdFilter = {
"second part"
}
}
def main(args: Array[String]) = {
val result : String = TestHandler.start()
System.out.println("result="+result)
}
}
trait MySuper {
protected def filter: String = {
"first part to->"
}
def start() = {
filter
}
}
trait MyTrait { self: MySuper =>
lazy val createdFilter = {
"override this"
}
protected override def filter: String = {
self.filter + createdFilter
}
}
This is scala 2.9. Any ideas what is going on here?
EDIT:
The stack trace makes no sense on how it jumps back and forth too(I should have included it in original post)...
at MyTrait$class.filter(TestingOutTraits.scala:34)
at TestingOutTraits$$anon$1.filter(TestingOutTraits.scala:4)
at MyTrait$class.filter(TestingOutTraits.scala:34)
at TestingOutTraits$$anon$1.filter(TestingOutTraits.scala:4)
thanks,
Dean
The call self.filter in MyTrait.filter invokes itself, leading to infinite recursion that blows the stack.
Instead, have MyTrait extend MySuper, and use super.filter:
trait MyTrait extends MySuper {
lazy val createdFilter = {
"override this"
}
protected override def filter: String = {
super.filter + createdFilter
}
}
Alternatively,
trait MySuper extends Filtered {
protected def filter: String = {
"first part to->"
}
def start() = {
filter
}
}
trait Filtered {
protected def filter: String
}
trait MyTrait extends Filtered {
lazy val createdFilter = {
"override this"
}
protected abstract override def filter: String = {
super.filter + createdFilter
}
}
then
val nope = new MyTrait { } // correctly DNC
and the OP
val TestHandler = new MySuper with MyTrait {
override lazy val createdFilter = {
"second part"
}
}
http://www.artima.com/pins1ed/traits.html#12.5
Well, I know why the infinite recursion though this seems like a linearization bug in scala and I am not sure how to work around it yet either :(.
hmmmm, so it turns out the compiler is sticking a filter method in my new Object for some reason. I found this out with the print:mixin on scalac like so
$ scalac -Xprint:mixin TestingOutTraits.scala
[[syntax trees at end of mixin]]// Scala source: TestingOutTraits.scala
package <empty> {
final object TestingOutTraits extends java.lang.Object with ScalaObject {
private[this] val TestHandler: MySuper = _;
<stable> <accessor> def TestHandler(): MySuper = TestingOutTraits.this.TestHandler;
def main(args: Array[java.lang.String]): Unit = {
val result: java.lang.String = TestingOutTraits.this.TestHandler().start();
java.this.lang.System.out.println("result=".+(result))
};
def this(): object TestingOutTraits = {
TestingOutTraits.super.this();
TestingOutTraits.this.TestHandler = {
new anonymous class TestingOutTraits$$anon$1()
};
()
}
};
abstract trait MySuper extends java.lang.Object with ScalaObject {
def filter(): java.lang.String;
def start(): java.lang.String
};
abstract trait MyTrait extends java.lang.Object with ScalaObject { self: MyTrait =>
def createdFilter(): java.lang.String;
override def filter(): java.lang.String
};
abstract trait MySuper$class extends {
def filter($this: MySuper): java.lang.String = "first part to->";
def start($this: MySuper): java.lang.String = $this.filter();
def /*MySuper$class*/$init$($this: MySuper): Unit = {
()
}
};
abstract trait MyTrait$class extends { self: MyTrait =>
def createdFilter($this: MyTrait): java.lang.String = "override this";
override def filter($this: MyTrait): java.lang.String = $this.$asInstanceOf[MySuper]().filter().+($this.createdFilter());
def /*MyTrait$class*/$init$($this: MyTrait): Unit = {
()
}
};
final class TestingOutTraits$$anon$1 extends java.lang.Object with MySuper with MyTrait {
override def filter(): java.lang.String = MyTrait$class.filter(TestingOutTraits$$anon$1.this);
def start(): java.lang.String = MySuper$class.start(TestingOutTraits$$anon$1.this);
override def createdFilter(): java.lang.String = "second part";
def this(): anonymous class TestingOutTraits$$anon$1 = {
TestingOutTraits$$anon$1.super.this();
MySuper$class./*MySuper$class*/$init$(TestingOutTraits$$anon$1.this);
MyTrait$class./*MyTrait$class*/$init$(TestingOutTraits$$anon$1.this);
()
}
}

Default type-parametrized function literal class parameter

Is this an intended behavior or is it a bug? Consider the following trait (be it a class, doesn't matter):
trait P[T] {
class Inner(val f: T => Unit = _ => println("nope"))
}
This is what I would have expected:
scala> val p = new P[Int] {
| val inner = new Inner
| }
p: java.lang.Object with P[Int]{def inner: this.Inner} = $anon$1#12192a9
scala> p.inner.f(5)
nope
But this?
scala> val p = new P[Int] {
| val inner = new Inner() {
| println("some primary constructor code in here")
| }
| }
<console>:6: error: type mismatch;
found : (T) => Unit
required: (Int) => Unit
val inner = new Inner() {
^
That appears to be a bug, albeit at a rather obscure intersection between nested classes, abstract types, and default parameters. You could raise a ticket in the Scala bug tracker -- I couldn't find an existing ticket describing this.
Here's how it looks after the typer phase:
~: scala -nocompdaemon -Xprint:typer -e 'trait P[T] { class Inner(val f: T = null.asInstanceOf[T]) }; new P[Int] { new Inner(){} }'
!!!
discarding <script preamble>
(fragment of scalacmd162105603941759154.scala):1: error: type mismatch;
found : T
required: Int
trait P[T] { class Inner(val f: T = null.asInstanceOf[T]) }; new P[Int] { new Inner(){} }
^
[[syntax trees at end of typer]]// Scala source: (virtual file)
package <empty> {
final object Main extends java.lang.Object with ScalaObject {
def this(): object Main = {
Main.super.this();
()
};
def main(argv: Array[String]): Unit = {
val args: Array[String] = argv;
{
final class $anon extends scala.AnyRef {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
abstract trait P[T >: Nothing <: Any] extends java.lang.Object with ScalaObject {
def /*P*/$init$(): Unit = {
()
};
class Inner extends java.lang.Object with ScalaObject {
<paramaccessor> private[this] val f: T = _;
<stable> <accessor> <paramaccessor> def f: T = Inner.this.f;
def this(f: T = null.asInstanceOf[T]): P.this.Inner = {
Inner.super.this();
()
}
};
final <synthetic> object Inner extends java.lang.Object with ScalaObject {
<synthetic> def init$default$1: T #scala.annotation.unchecked.uncheckedVariance = null.asInstanceOf[T];
def this(): object P.this.Inner = {
Inner.super.this();
()
}
}
};
{
final class $anon extends java.lang.Object with this.P[Int] {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
{
final class $anon extends $anon.this.Inner {
def this(): anonymous class $anon = {
$anon.super.this(P.this.Inner.<error: method init$default$1>);
()
};
<empty>
};
new $anon()
}
};
new $anon()
}
};
{
new $anon();
()
}
}
}
}
}
And the working version, without the anonymous inner class extending Inner.
~: scala -nocompdaemon -Xprint:typer -e 'trait P[T] { class Inner(val f: T = null.asInstanceOf[T]) }; new P[Int] { new Inner() }'
[[syntax trees at end of typer]]// Scala source: (virtual file)
package <empty> {
final object Main extends java.lang.Object with ScalaObject {
def this(): object Main = {
Main.super.this();
()
};
def main(argv: Array[String]): Unit = {
val args: Array[String] = argv;
{
final class $anon extends scala.AnyRef {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
abstract trait P[T >: Nothing <: Any] extends java.lang.Object with ScalaObject {
def /*P*/$init$(): Unit = {
()
};
class Inner extends java.lang.Object with ScalaObject {
<paramaccessor> private[this] val f: T = _;
<stable> <accessor> <paramaccessor> def f: T = Inner.this.f;
def this(f: T = null.asInstanceOf[T]): P.this.Inner = {
Inner.super.this();
()
}
};
final <synthetic> object Inner extends java.lang.Object with ScalaObject {
<synthetic> def init$default$1: T #scala.annotation.unchecked.uncheckedVariance = null.asInstanceOf[T];
def this(): object P.this.Inner = {
Inner.super.this();
()
}
}
};
{
final class $anon extends java.lang.Object with this.P[Int] {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
new $anon.this.Inner($anon.this.Inner.init$default$1)
};
new $anon()
}
};
{
new $anon();
()
}
}
}
}
}