Difference between Scala 2 implicits and Scala 3 given/using - scala

What is the difference between the implicit keyword in Scala 2 and given+using in Scala 3? Is it just that implicit has been split up into two keywords, or are the semantics also different, and if so, how?

For the most part, they are the same. However, implicit is no longer used for multiple different concepts. The docs go into more detail, but here's a summary of them:
Using
When declaring parameters, using is just the same as implicit. However, when explicitly passing an implicit argument, you must use using:
def foo(using bar: Bar) = ???
foo(using Bar()) //Cannot use just foo(Bar()) as you would in Scala 2
You can also have implicit by-name parameters in Scala 3.
Given
Givens are also pretty similar to implicit vals/objects/methods.
One nice thing about them is that they can be anonymous, and the compiler will generate a name for them, which looks something like given_F_X_Y if the type of the given were F[X, Y]. More details here.
Another change is that the type of a given must be written explicitly - it cannot be inferred like for an implicit in Scala 2.
A given without parameters maps to an implicit object. given foo: Foo with {...} becomes just implicit object foo extends Foo {...}.
A given with parameters is akin to an implicit def that takes in only more implicit parameters.
given listOrd[T](using ord: Ord[T]): Ord[List[T]] with { ... }
//^^ this maps to this vv
class listOrd[T](implicit ord: Ord[T]) extends Ord[List[T]] { ... }
final implicit def listOrd[T](implicit ord: Ord[T]): listOrd[T] = new listOrd[T]
A given that is merely an alias becomes an implicit def if it is just a reference, or an implicit lazy val otherwise.
val foo: Foo
given Foo = foo
would become final implicit def given_Foo = foo (note the compiler-generated name), but
given foo: Foo = new Foo()
would turn into final implicit lazy val foo: Foo = new Foo() because new Foo() shouldn't be computed unnecessarily.
Instead of using an implicit def for an implicit conversion from A to B, you can now define a given Conversion[A, B] instance.
You can also still use implicit classes in Dotty, but you can directly define extension methods. While methods inside extensions cannot take their own type parameters, they are easier to use than implicit classes.
An additional change in Scala 3 - summon is a method like implicitly, but it can return a type more specific than the one being requested.

Semantics is also different. In Scala 2 Not can be defined with ambiguity trick
trait Not[A]
object Not {
implicit def default[A]: Not[A] = null
implicit def ambig[A](implicit a: A): Not[A] = null
}
implicitly[Not[Int]] // compiles
implicit val s: String = null
// implicitly[Not[String]] // doesn't compile
But in Scala 3 this doesn't work because ambiguity error is not propagated
trait Not[A]
object Not {
given [A]: Not[A] = null
given [A](using a: A): Not[A] = null
// given ambig[A](using a: A): Not[A] = null
}
summon[Not[Int]] // compiles
given String = null
summon[Not[String]] // compiles
One should use scala.util.NotGiven instead
summon[NotGiven[Int]] // compiles
given String = null
// summon[NotGiven[String]] // doesn't compile
(Tested in 3.0.0-M3-bin-20201211-dbc1186-NIGHTLY)
http://dotty.epfl.ch/docs/reference/contextual/givens.html#negated-givens
http://dotty.epfl.ch/docs/reference/changed-features/implicit-resolution.html

Related

scala overloading resolution differences between function calls and implicit search

There is a difference in the way the scala 2.13.3 compiler determines which overloaded function to call compared to which overloaded implicit to pick.
object Thing {
trait A;
trait B extends A;
trait C extends A;
def f(a: A): String = "A"
def f(b: B): String = "B"
def f(c: C): String = "C"
implicit val a: A = new A {};
implicit val b: B = new B {};
implicit val c: C = new C {};
}
import Thing._
scala> f(new B{})
val res1: String = B
scala> implicitly[B]
val res2: Thing.B = Thing$$anon$2#2f64f99f
scala> f(new A{})
val res3: String = A
scala> implicitly[A]
^
error: ambiguous implicit values:
both value b in object Thing of type Thing.B
and value c in object Thing of type Thing.C
match expected type Thing.A
As we can see, the overload resolution worked for the function call but not for the implicit pick. Why isn't the implicit offered by val a be chosen as occurs with function calls? If the callers ask for an instance of A why the compilers considers instances of B and C when an instance of A is in scope. There would be no ambiguity if the resolution logic were the same as for function calls.
Edit 2:
The Edit 1 was removed because the assertion I wrote there was wrong.
In response to the comments I added another test to see what happens when the implicit val c: C is removed. In that case the compiler don't complains and picks implicit val b: B despite the caller asked for an instance of A.
object Thing {
trait A { def name = 'A' };
trait B extends A { def name = 'B' };
trait C extends A { def name = 'C' };
def f(a: A): String = "A"
def f(b: B): String = "B"
implicit val a: A = new A {};
implicit val b: B = new B {};
}
import Thing._
scala> f(new A{})
val res0: String = A
scala> implicitly[A].name
val res3: Char = B
So, the overloading resolution of implicit differs from function calls more than I expected.
Anyway, I still don't find a reason why the designers of scala decided to apply a different resolution logic for function and implicit overloading. (Edit: Later noticed why).
Let's see what happens in a real world example.
Suppose we are doing a Json parser that converts a Json string directly to scala Abstract data types, and we want it to support many standard collections.
The snippet in charge of parsing the iterable collections would be something like this:
trait Parser[+A] {
def parse(input: Input): ParseResult;
///// many combinators here
}
implicit def summonParser[T](implicit parserT: Parser[T]) = parserT;
/** #tparam IC iterator type constructor
* #tparam E element's type */
implicit def iterableParser[IC[E] <: Iterable[E], E](
implicit
parserE: Parser[E],
factory: IterableFactory[IC]
): Parser[IC[E]] = '[' ~> skipSpaces ~> (parserE <~ skipSpaces).repSepGen(coma <~ skipSpaces, factory.newBuilder[E]) <~ skipSpaces <~ ']';
Which requires a Parser[E] for the elements and a IterableFactory[IC] to construct the collection specified by the type parameters.
So, we have to put in implicit scope an instance of IterableFactory for every collection type we want to support.
implicit val iterableFactory: IterableFactory[Iterable] = Iterable
implicit val setFactory: IterableFactory[Set] = Set
implicit val listFactory: IterableFactory[List] = List
With the current implicit resolution logic implemented by the scala compiler, this snippet works fine for Set and List, but not for Iterable.
scala> def parserInt: Parser[Int] = ???
def parserInt: read.Parser[Int]
scala> Parser[List[Int]]
val res0: read.Parser[List[Int]] = read.Parser$$anonfun$pursue$3#3958db82
scala> Parser[Vector[Int]]
val res1: read.Parser[Vector[Int]] = read.Parser$$anonfun$pursue$3#648f48d3
scala> Parser[Iterable[Int]]
^
error: could not find implicit value for parameter parserT: read.Parser[Iterable[Int]]
And the reason is:
scala> implicitly[IterableFactory[Iterable]]
^
error: ambiguous implicit values:
both value listFactory in object IterableParser of type scala.collection.IterableFactory[List]
and value vectorFactory in object IterableParser of type scala.collection.IterableFactory[Vector]
match expected type scala.collection.IterableFactory[Iterable]
On the contrary, if the overloading resolution logic of implicits was like the one for function calls, this would work fine.
Edit 3: After many many coffees I noticed that, contrary to what I said above, there is no difference between the way the compiler decides which overloaded functions to call and which overloaded implicit to pick.
In the case of function call: from all the functions overloads such that the type of the argument is asignable to the type of the parameter, the compiler chooses the one such that the function's parameter type is assignable to all the others. If no function satisfies that, a compilation error is thrown.
In the case of implicit pick up: from all the implicit in scope such that the type of the implicit is asignable to the asked type, the compiler chooses the one such that the declared type is asignable to all the others. If no implicit satisfies that, an compilation error is thrown.
My mistake was that I didn't notice the inversion of the assignability.
Anyway, the resolution logic I proposed above (give me what I asked for) is not entirely wrong. It's solves the particular case I mentioned. But for most uses cases the logic implemented by the scala compiler (and, I suppose, all the other languages that support type classes) is better.
As explained in the Edit 3 section of the question, there are similitudes between the way the compiler decides which overloaded functions to call and which overloaded implicit to pick. In both cases the compiler does two steps:
Filters out all the alternatives that are not asignable.
From the remaining alternatives choses the most specific or complains if there is more than one.
In the case of the function call, the most specific alternative is the function with the most specific parameter type; and in the case of implicit pick is the instance with the most specific declared type.
But, if the logic in both cases were exactly the same, then why did the example of the question give different results? Because there is a difference: the assignability requirement that determines which alternatives pass the first step are oposite.
In the case of the function call, after the first step remain the functions whose parameter type is more generic than the argument type; and in the case of implicit pick, remain the instances whose declared type is more specific than the asked type.
The above words are enough to answers the question itself but don't give a solution to the problem that motivated it, which is: How to force the compiler to pick the implicit instance whose declared type is exactly the same than the summoned type? And the answer is: wrapping the implicit instances inside a non variant wrapper.

How can I write a function have a polymorphic return type based on the type argument of its type parameter?

I have some code like this:
sealed trait Foo[A] {
def value: A
}
case class StringFoo(value: String) extends Foo[String]
case class IntFoo(value: Int) extends Foo[Int]
I'd like to have a function which can use the A type given a subtype's type parameter.
// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
I can't figure out how to declare dostuff in a way that works. The closest thing I can figure out is
def dostuff[B <: Foo[A]](p: Param): A
But that doesn't work because A is undefined in that position. I can do something like
def dostuff[A, B <: Foo[A]](p: Param): A
But then I have to invoke it like dostuff[String, StringFoo](param) which is pretty ugly.
It seems like the compiler should have all the information it needs to move A across to the return type, how can I make this work, either in standard scala or with a library. I'm on scala 2.10 currently if that impacts the answer. I'm open to a 2.11-only solution if it's possible there but impossible in 2.10
Another option is to use type members:
sealed trait Foo {
type Value
def value: Value
}
case class StringFoo(value: String) extends Foo { type Value = String }
case class IntFoo(value: Int) extends Foo { type Value = Int }
def dostuff[B <: Foo](p: Any): B#Value = ???
// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
Note that both solutions mainly work around the syntactic restriction in Scala, that you cannot fix one type parameter of a list and have the compiler infer the other.
As you might know, if you have a parameter of type Foo[A], then you can make the method generic in just A:
def dostuff[A](p: Foo[A]): A = ???
Since that might not always be the case, we can try to use an implicit parameter that can express the relationship between A and B. Since we can't only apply some of the generic parameters to a method call (generic parameter inference is all or nothing), we have to split this into 2 calls. This is an option:
case class Stuff[B <: Foo[_]]() {
def get[A](p: Param)(implicit ev: B => Foo[A]): A = ???
}
You can check the types in the REPL:
:t Stuff[IntFoo].get(new Param) //Int
:t Stuff[StringFoo].get(new Param) //String
Another option along the same lines, but using an anonymous class, is:
def stuff[B <: Foo[_]] = new {
def apply[A](p: Param)(implicit ev: B <:< Foo[A]): A = ???
}
:t stuff[IntFoo](new Param) //Int
Here, I've used apply in stead of get, so you can apply the method more naturally. Also, as suggested in your comment, here I've used <:< in the evidence type. For those looking to learn more about this type of generalized type constraint, you can read more here.
You might also consider using abstract type members instead of generic parameters here. When struggling with generic type inference, this often provides an elegant solution. You can read more about abstract type members and their relationship to generics here.

Enforce a lower-bounds that "excludes" a super type

Bounds in Scala allow more granular control of types in Scala, for example argument types.
For example
def foo[ S <: String ]( arg: S ): S = ...
The above allows a function to accept arguments that are sub types of String, also
def bar[ S >: A <: B ]( arg: S ): S = ...
The above allows the setting of an upper and lower bound so that S is a sub type of B and a super type of A.
My question is (I assume the bounds are inclusive) would it be possible to set up an argument type so that the argument would be a supertype of say String, but not include some super type of the lower bound (in this case String) say type Any.
UPDATE
sealed trait Helper[S]
object Helper {
implicit def stringSubtype[S >: String] = new Helper[S]{}
implicit def any = new Helper[Any]{}
}
def foo[S: Helper](r: S): Int = 1
val arg1: String = "hi"
val arg2: Any = "hello"
foo(arg1)
foo(arg2)
I would expect that the call with arg2 should result in an illegal argument exception.
For more complex type constraints like this you can do type-level programming via implicits:
sealed trait Helper[S]
object Helper {
implicit def stringSubtype[S >: String] = new Helper[S]{}
implicit def any = new Helper[Any]{}
implicit def any2 = new Helper[Any]{}
}
def foo[S: Helper] = ...
foo can only be invoked with a type S for which an implicit Helper[S] can be resolved. stringSubtype supplies a Helper[S] for any S >: String. But for Any, both that and any apply and the two implicits conflict, so it's not possible (well, except by explicitly passing one or the other) to call foo[Any].
Update: it seems that any is somehow higher priority than stringSubtype, so it's resolved for foo[Any]. Rather than figure out exactly why this is, the simplest workaround was to also define any2.

Scala: How to make case class copy keep manifest information

A case classes copy() method is supposed to make an identical copy of the instance, plus replacing any fields by name. This seems to fail when the case class has type parameters with manifests. The copy loses all knowledge of the types of its parameters.
case class Foo[+A : Manifest](a: A) {
// Capture manifest so we can observe it
// A demonstration with collect would work equally well
def myManifest = implicitly[Manifest[_ <: A]]
}
case class Bar[A <: Foo[Any]](foo: A) {
// A simple copy of foo
def fooCopy = foo.copy()
}
val foo = Foo(1)
val bar = Bar(foo)
println(bar.foo.myManifest) // Prints "Int"
println(bar.fooCopy.myManifest) // Prints "Any"
Why does Foo.copy lose the manifest on the parameters and how do I make it retain it?
Several Scala peculiarities interact to give this behavior. The first thing is that Manifests are not only appended to the secret implicit parameter list on the constructor but also on the copy method. It is well known that
case class Foo[+A : Manifest](a: A)
is just syntactic sugar for
case class Foo[+A](a: A)(implicit m: Manifest[A])
but this also affects the copy constructor, which would look like this
def copy[B](a: B = a)(implicit m: Manifest[B]) = Foo[B](a)(m)
All those implicit ms are created by the compiler and sent to the method through the implicit parameter list.
This would be fine as long as one was using the copy method in a place where the compiler knew Foos type parameter. For example, this will work outside of the Bar class:
val foo = Foo(1)
val aCopy = foo.copy()
println(aCopy.myManifest) // Prints "Int"
This works because the compiler infers that foo is a Foo[Int] so it knows that foo.a is an Int so it can call copy like this:
val aCopy = foo.copy()(manifest[Int]())
(Note that manifest[T]() is a function that creates a manifest representation of the type T, e.g. Manifest[T] with a capital "M". Not shown is the addition of the default parameter into copy.) It also works within the Foo class because it already has the manifest that was passed in when the class was created. It would look something like this:
case class Foo[+A : Manifest](a: A) {
def myManifest = implicitly[Manifest[_ <: A]]
def localCopy = copy()
}
val foo = Foo(1)
println(foo.localCopy.myManifest) // Prints "Int"
In the original example, however, it fails in the Bar class because of the second peculiarity: while the type parameters of Bar are known within the Bar class, the type parameters of the type parameters are not. It knows that A in Bar is a Foo or a SubFoo or SubSubFoo, but not if it is a Foo[Int] or a Foo[String]. This is, of course, the well-known type erasure problem in Scala, but it appears as a problem here even when it doesn't seem like the class is doing anything with the type of foos type parameter. But it is, remember there is a secret injection of a manifest every time copy is called, and those manifests overwrite the ones that were there before. Since the Bar class has no idea was the type parameter of foo is, it just creates a manifest of Any and sends that along like this:
def fooCopy = foo.copy()(manifest[Any])
If one has control over the Foo class (e.g. it's not List) then one workaround it by doing all the copying over in the Foo class by adding a method that will do the proper copying, like localCopy above, and return the result:
case class Bar[A <: Foo[Any]](foo: A) {
//def fooCopy = foo.copy()
def fooCopy = foo.localCopy
}
val bar = Bar(Foo(1))
println(bar.fooCopy.myManifest) // Prints "Int"
Another solution is to add Foos type parameter as a manifested type parameter of Bar:
case class Bar[A <: Foo[B], B : Manifest](foo: A) {
def fooCopy = foo.copy()
}
But this scales poorly if class hierarchy is large, (i.e. more members have type parameters, and those classes also have type parameters) since every class would have to have the type parameters of every class below it. It also seems to make the type inference freak out when trying to construct a Bar:
val bar = Bar(Foo(1)) // Does not compile
val bar = Bar[Foo[Int], Int](Foo(1)) // Compiles
There are two problems as you identified. The first problem is the type erasure problem inside of Bar, where Bar doesn't know the type of Foo's manifest. I would personally use the localCopy workaround you suggested.
The second issue is that another implicit is being secretly injected into copy. That issue is resolved by explicitly passing the value again into the copy. For example:
scala> case class Foo[+A](a: A)(implicit val m: Manifest[A #uncheckedVariance])
defined class Foo
scala> case class Bar[A <: Foo[Any]](foo: A) {
| def fooCopy = foo.copy()(foo.m)
| }
defined class Bar
scala> val foo = Foo(1)
foo: Foo[Int] = Foo(1)
scala> val bar = Bar(foo)
bar: Bar[Foo[Int]] = Bar(Foo(1))
scala> bar.fooCopy.m
res2: Manifest[Any] = Int
We see the copy has kept the Int manifest but the type of fooCopy and res2 is Manifest[Any] due to erasure.
Because I needed access to the implicit evidence to do the copy I had to use the explicit implicit (hah) syntax instead of the context bound syntax. But using the explicit syntax caused errors:
scala> case class Foo[+A](a: A)(implicit val m: Manifest[A])
<console>:7: error: covariant type A occurs in invariant position in type => Manifest[A] of value m
case class Foo[+A](a: A)(implicit val m: Manifest[A])
^
scala> case class Foo[+A](a: A)(implicit val m: Manifest[_ <: A])
defined class Foo
scala> val foo = Foo(1)
<console>:9: error: No Manifest available for Int.
WTF? How come the context bound syntax works and the explicit implicit doesn't? I dug around and found a solution to the problem: the #uncheckedVariance annotation.
UPDATE
I dug around some more and found that in Scala 2.10 case classes have been changed to only copy the fields from the first parameter list in copy().
Martin says: case class ness is only bestowed on the first argument
list the rest should not be copied.
See the details of this change at https://issues.scala-lang.org/browse/SI-5009.

Why does Scala's type inferencer fail with this set of implicit arguments involving parameterized types?

I would like to define a method parameterized with type T that has behavior dependent on what implicit argument can be found of type Box[T]. The following code has this method defined as foo. When called with foo[Int] or foo[String] it will without issue return 1 or "two" as expected.
Where things get weird is with the method bar. It is defined as returning an Int, but instead of foo[Int] I have just foo. My hope was that the compiler would infer that T must be of type Int. It does not do that and instead fails:
bash $ scalac Code.scala
Types.scala:15: error: ambiguous implicit values:
both value one in object Main of type => Main.Box[Int]
and value two in object Main of type => Main.Box[java.lang.String]
match expected type Main.Box[T]
def bar: Int = foo
^
one error found
What is causing this error? Replacing foo with foo[Int] compiles fine. The simpler situation where there is no Box[T] type also compiles fine. That example is also below and uses argle and bargle instead of foo and bar.
object Main extends Application {
case class Box[T](value: T)
implicit val one = Box(1)
implicit val two = Box("two")
def foo[T](implicit x: Box[T]): T = {
x.value
}
// does not compile:
// def bar: Int = foo
// does compile
def bar: Int = foo[Int]
println(bar)
// prints 1
// the simpler situation where there is no Box type
implicit val three = 3
implicit val four = "four"
def argle[T](implicit x: T): T = x
def bargle: String = argle
println(bargle)
// prints "four"
}
What is going on in this snippet that causes this behavior? What about this interaction of implicit arguments, type inference, and erasure is causing problems? Is there a way to modify this code such that the line def foo: Int = bar works?
Someone else will have to explain why the type inference mechanism cannot handle that case, but if you are looking to cleanup your code you could probably do this:
object Test extends App {
case class Box[T](value: T)
implicit val one: Box[Int] = Box(1)
implicit val two: Box[String] = Box("two")
def foo[T : Box]: T = implicitly[Box[T]].value
val bar = foo[Int]
}
Note that:
I removed the type annotation from bar so you are really just indicating the type once (just in a different spot than you wanted)
I am using App instead of deprecated Application
Using a context bound in the type signature of foo
This might be related to SI-3346, though there it is implicit arguments to implicit conversions, and here you have a single implicit.