This question already has an answer here:
What does ?=> mean in Scala?
(1 answer)
Closed 1 year ago.
I cannot find explanation of the following syntax rule:
FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
?=> denotes a context function type.
Context functions are written using ?=> as the “arrow” sign. They are applied to synthesized arguments, in the same way methods with context parameters are applied. For instance:
given ec: ExecutionContext = ...
def f(x: Int): ExecutionContext ?=> Int = ...
...
f(2)(using ec) // explicit argument
f(2) // argument is inferred
So, if you think of A => B as being analogous to
def foo(a: A): B
Then you should think of A ?=> B as being analogous to
def foo(using a: A): B
It's just like a regular function except that the argument is taken as a context parameter. You can refuse to supply it (and it will be inferred from all of the givens in-scope, similar to implicit in Scala 2), or you can explicitly supply it using the using keyword.
Related
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.
This question already has answers here:
Understanding implicit in Scala
(7 answers)
Closed 2 years ago.
I have to solve this quinz but i can't find the correct answer.
trait Physics {
implicit def air: Gaz,
implicit def condense(implicit gaz: Gaz): Liquid,
implicit def freeze(implicit liquid: Liquid): Solid
implicitly[Solid]
}
Can you rewrite the last line with the inferred parameter explicitly written?
Hint: It should look like
implicitly[Solid](...
Thank you so much!
Here is a hint: first consider implicitly is just a method like any other
def implicitly[T](implicit e: T): T = e
Lets remove the keyword implicit such that
def implicitly[T](e: T): T = e
Given implicitly is just a method taking arguments, think about what would you have to do to make compiler happy and have method implicitly return a Solid?
In the spec of scala 6.26.2, there are 4 kind of conversions for methods:
MethodConversions
The following four implicit conversions can be applied to methods which are not applied to some argument list.
Evaluation. A parameterless method m of type => T is always converted to type T by evaluating the expression to which m is bound.
Implicit Application. If the method takes only implicit parameters, implicit argu- ments are passed following the rules of §7.2.
Eta Expansion. Otherwise, if the method is not a constructor, and the expected type pt is a function type (Ts′) ⇒ T′, eta-expansion (§6.26.5) is performed on the expression e.
Empty Application. Otherwise, if e has method type ()T , it is implicitly applied to the empty argument list, yielding e().
Some scala code:
def hello(): String = "abc"
def world1(s: String) = s
def world2(s: => String) = s
def world3(s: () => String) = s
world1(hello)
world2(hello)
world3(hello)
My question is, for world1, world2 and world3, which conversion rule is applied to each of them?
def world1(s: String) = s
world1(hello)
Empty application: hello is evaluated as hello() and then passed as the argument of world1
def world2(s: => String) = s
world2(hello)
Eta-expansion + Evaluation: hello is expanded into a function and evaluated lazily.
def world3(s: () => String) = s
world3(hello)
Eta-expansion: hello is expanded to a Function0[String]
Eta-expansion is necessary because methods and functions are two different things, even though the scala compiler is very good at hiding this difference.
The difference comes from the fact that methods are a JVM concept, whereas first-class functions are a scala-specific concept.
You can try this out in a REPL. First, let's define a method hello
scala> def hello(s: String) = s"hello $s"
hello: (s: String)String
scala> hello.hashCode
<console>:9: error: missing arguments for method hello;
follow this method with `_' if you want to treat it as a partially applied function
hello.hashCode
^
Woops, hello is not a value (in the JVM sense)! Not having an hashcode is a proof of it.
Let's get a Function1 out of the hello method
scala> hello _
res10: String => String = <function1>
scala> (hello _).hashCode
res11: Int = 1710358635
A function is a value, so it has an hashcode.
In Learning Scalaz there is a type parameter on the method sum.
Does this mean that the type A is of type Monoid? However that seems wrong, if the type A is a Monoid then how can it also be an integer as it is used in the example. I must be reading the type parameter wrong.
What is the meaning of the type parameter? How should I be reading it?
def sum[A: Monoid](xs: List[A]): A = {
val m = implicitly[Monoid[A]]
xs.foldLeft(m.mzero)(m.mappend)
}
A: Monoid is a type parameter with a Context Bound. It's syntactic sugar.
The following:
def sum[A: Monoid](xs: List[A]): A
gets desugared into:
def sum[A](xs: List[A])(implicit val $ev: Monoid[A]): A
I compile the following code
def foo(implicit x: Int, x2: Int) = println(x2 + x)
implicit val x : Int = 2
foo(1)
But the compiler moans about the number of arguments. Why would the above work if there was only parameter x marked as implicit, but it does not work in this example?
You have to put the implicit argument is a separated, its own parenthesis:
scala> def foo(x2: Int)(implicit x: Int) = println(x2 + x)
scala> implicit val x: Int 2
scala> foo(1)
3
If you put non implicit argument and implicit argument in the same parenthesis, you have to explicitly pass both arguments otherwise compiler will complain about the wrong number of arguments. Scala compiler will try to look for implicit arguments when it sees that the argument is marked as implicit and no argument has been passed explicitly. But compiler checks if the right number of argument has been passed before checking for the implicit.
This will work as you want:
def foo(x2: Int)(implicit x: Int) = println(x2 + x)
implicit val x : Int = 2
foo(1)
I'm not too deep into Scala internals and spec so I cannot give an in depth-explanation why this is, but you have to pass implicits with an extra set of parenthesis.
Edit:
Because I was curious I had a look around the interwebs. I will not retype all the stuff I just found myself so you can find more detailed information here: http://daily-scala.blogspot.de/2010/04/implicit-parameters.html
Implicit parameters are all-or-nothing. Either you pass all of them explicitly, or you don't pass any of them and the compiler picks implicits for all.
In the example you should you are passing a parameter to foo, so you have to pass everything. If you had only one parameter in foo, it would work because the number of parameters is correct (and the parameter would be passed explicitly). If you call foo without passing any parameters, it will also work because it will pick implicit val x for both parameters.