Magnet pattern and overloaded methods - scala

There is a significant difference in how Scala resolves implicit conversions from "Magnet Pattern" for non-overloaded and overloaded methods.
Suppose there is a trait Apply (a variation of a "Magnet Pattern") implemented as follows.
trait Apply[A] {
def apply(): A
}
object Apply {
implicit def fromLazyVal[A](v: => A): Apply[A] = new Apply[A] {
def apply(): A = v
}
}
Now we create a trait Foo that has a single apply taking an instance of Apply so we can pass it any value of arbitrary type A since there an implicit conversion from A => Apply[A].
trait Foo[A] {
def apply(a: Apply[A]): A = a()
}
We can make sure it works as expected using REPL and this workaround to de-sugar Scala code.
scala> val foo = new Foo[String]{}
foo: Foo[String] = $anon$1#3a248e6a
scala> showCode(reify { foo { "foo" } }.tree)
res9: String =
$line21$read.foo.apply(
$read.INSTANCE.Apply.fromLazyVal("foo")
)
This works great, but suppose we pass a complex expression (with ;) to the apply method.
scala> val foo = new Foo[Int]{}
foo: Foo[Int] = $anon$1#5645b124
scala> var i = 0
i: Int = 0
scala> showCode(reify { foo { i = i + 1; i } }.tree)
res10: String =
$line23$read.foo.apply({
$line24$read.`i_=`($line24$read.i.+(1));
$read.INSTANCE.Apply.fromLazyVal($line24$read.i)
})
As we can see, an implicit conversion has been applied only on the last part of the complex expression (i.e., i), not to the whole expression. So, i = i + 1 was strictly evaluated at the moment we pass it to an apply method, which is not what we've been expecting.
Good (or bad) news. We can make scalac to use the whole expression in the implicit conversion. So i = i + 1 will be evaluated lazily as expected. To do so we (surprize, surprize!) we add an overload method Foo.apply that takes any type, but not Apply.
trait Foo[A] {
def apply(a: Apply[A]): A = a()
def apply(s: Symbol): Foo[A] = this
}
And then.
scala> var i = 0
i: Int = 0
scala> val foo = new Foo[Int]{}
foo: Foo[Int] = $anon$1#3ff00018
scala> showCode(reify { foo { i = i + 1; i } }.tree)
res11: String =
$line28$read.foo.apply($read.INSTANCE.Apply.fromLazyVal({
$line27$read.`i_=`($line27$read.i.+(1));
$line27$read.i
}))
As we can see, the entire expression i = i + 1; i made it under the implicit conversion as expected.
So my question is why is that? Why the scope of which an implicit conversion is applied depends on the fact whether or not there is an overloaded method in the class.

Now, that is a tricky one. And it's actually pretty awesome, I didn't know that "workaround" to the "lazy implicit does not cover full block" problem. Thanks for that!
What happens is related to expected types, and how they affect type inference works, implicit conversions, and overloads.
Type inference and expected types
First, we have to know that type inference in Scala is bi-directional. Most of the inference works bottom-up (given a: Int and b: Int, infer a + b: Int), but some things are top-down. For example, inferring the parameter types of a lambda is top-down:
def foo(f: Int => Int): Int = f(42)
foo(x => x + 1)
In the second line, after resolving foo to be def foo(f: Int => Int): Int, the type inferencer can tell that x must be of type Int. It does so before typechecking the lambda itself. It propagates type information from the function application down to the lambda, which is a parameter.
Top-down inference basically relies on the notion of expected type. When typechecking a node of the AST of the program, the typechecker does not start empty-handed. It receives an expected type from "above" (in this case, the function application node). When typechecking the lambda x => x + 1 in the above example, the expected type is Int => Int, because we know what parameter type is expected by foo. This drives the type inference into inferring Int for the parameter x, which in turn allows to typecheck x + 1.
Expected types are propagated down certain constructs, e.g., blocks ({}) and the branches of ifs and matches. Hence, you could also call foo with
foo({
val y = 1
x => x + y
})
and the typechecker is still able to infer x: Int. That is because, when typechecking the block { ... }, the expected type Int => Int is passed down to the typechecking of the last expression, i.e., x => x + y.
Implicit conversions and expected types
Now, we have to introduce implicit conversions into the mix. When typechecking a node produces a value of type T, but the expected type for that node is U where T <: U is false, the typechecker looks for an implicit T => U (I'm probably simplifying things a bit here, but the gist is still true). This is why your first example does not work. Let us look at it closely:
trait Foo[A] {
def apply(a: Apply[A]): A = a()
}
val foo = new Foo[Int] {}
foo({
i = i + 1
i
})
When calling foo.apply, the expected type for the parameter (i.e., the block) is Apply[Int] (A has already been instantiated to Int). We can "write" this typechecker "state" like this:
{
i = i + 1
i
}: Apply[Int]
This expected type is passed down to the last expression of the block, which gives:
{
i = i + 1
(i: Apply[Int])
}
at this point, since i: Int and the expected type is Apply[Int], the typechecker finds the implicit conversion:
{
i = i + 1
fromLazyVal[Int](i)
}
which causes only i to be lazified.
Overloads and expected types
OK, time to throw overloads in there! When the typechecker sees an application of an overload method, it has much more trouble deciding on an expected type. We can see that with the following example:
object Foo {
def apply(f: Int => Int): Int = f(42)
def apply(f: String => String): String = f("hello")
}
Foo(x => x + 1)
gives:
error: missing parameter type
Foo(x => x + 1)
^
In this case, the failure of the typechecker to figure out an expected type causes the parameter type not to be inferred.
If we take your "solution" to your issue, we have a different consequence:
trait Foo[A] {
def apply(a: Apply[A]): A = a()
def apply(s: Symbol): Foo[A] = this
}
val foo = new Foo[Int] {}
foo({
i = i + 1
i
})
Now when typechecking the block, the typechecker has no expected type to work with. It will therefore typecheck the last expression without expression, and eventually typecheck the whole block as an Int:
{
i = i + 1
i
}: Int
Only now, with an already typechecked argument, does it try to resolve the overloads. Since none of the overloads conforms directly, it tries to apply an implicit conversion from Int to either Apply[Int] or Symbol. It finds fromLazyVal[Int], which it applies to the entire argument. It does not push it inside the block anymore, giving:
fromLazyVal({
i = i + 1
i
}): Apply[Int]
In this case, the whole block is lazified.
This concludes the explanation. To summarize, the major difference is the presence vs absence of an expected type when typechecking the block. With an expected type, the implicit conversion is pushed down as much as possible, down to just i. Without the expected type, the implicit conversion is applied a posteriori on the entire argument, i.e., the whole block.

Related

How to reference parameter of a higher kinded type parameteter?

Suppose you have a trait like this:
trait Foo[A]{
def foo: A
}
I want to create a function like this:
def getFoo[A <: Foo[_]](a: A) = a.foo
The Scala Compiler deduces Any for the return type of this function.
How can I reference the anonymous parameter _ in the signature (or body) of getFoo?
In other words, how can I un-anonymize the parameter?
I want to be able to use the function like
object ConcreteFoo extends Foo[String] {
override def foo: String = "hello"
}
val x : String = getFoo(ConcreteFoo)
which fails compilation for obvious reasons, because getFoo is implicitly declared as Any.
If this is not possible with Scala (2.12 for that matter), I'd be interested in the rational or the technical reason for this limitation.
I am sure there are articles and existing questions about this, but I appear to be lacking the correct search terms.
Update: The existing answer accurately answers my question as stated, but I suppose I wasn't accurate enough regarding my actual usecase. Sorry for the confusion. I want to be able to write
def getFoo[A <: Foo[_]] = (a: A) => a.foo
val f = getFoo[ConcreteFoo.type]
//In some other, unrelated place
val x = f(ConcreteFoo)
Because I don't have a parameter of type A, the compiler can't deduce the parameters R and A if I do
def getFoo[R, A <: Foo[R]]: (A => R) = (a: A) => a.foo
like suggested. I would like to avoid manually having to supply the type parameter R (String in this case), because it feels redundant.
To answer literally your exact question:
def getFoo[R, A <: Foo[R]](a: A): R = a.foo
But since you don't make any use of the type A, you can actually omit it and the <: Foo[..] bound completely, retaining only the return type:
def getFoo[R](a: Foo[R]): R = a.foo
Update (the question has been changed quite significantly)
You could smuggle in an additional apply invocation that infers the return type from a separate implicit return type witness:
trait Foo[A] { def foo: A }
/** This is the thing that remembers the actual return type of `foo`
* for a given `A <: Foo[R]`.
*/
trait RetWitness[A, R] extends (A => R)
/** This is just syntactic sugar to hide an additional `apply[R]()`
* invocation that infers the actual return type `R`, so you don't
* have to type it in manually.
*/
class RetWitnessConstructor[A] {
def apply[R]()(implicit w: RetWitness[A, R]): A => R = w
}
def getFoo[A <: Foo[_]] = new RetWitnessConstructor[A]
Now it looks almost like what you wanted, but you have to provide the implicit, and you have to call getFoo[ConcreteFoo.type]() with additional pair of round parens:
object ConcreteFoo extends Foo[String] {
override def foo: String = "hey"
}
implicit val cfrw = new RetWitness[ConcreteFoo.type, String] {
def apply(c: ConcreteFoo.type): String = c.foo
}
val f = getFoo[ConcreteFoo.type]()
val x: String = f(ConcreteFoo)
I'm not sure whether it's really worth it, it's not necessarily the most straightforward thing to do. Type-level computations with implicits, hidden behind somewhat subtle syntactic sugar: that might be too much magic hidden behind those two parens (). Unless you expect that the return type of foo will change very often, it might be easier to just add a second generic argument to getFoo, and write out the return type explicitly.

Confused about seemingly superfluous respecification of a variable's type in a genericized scala function

I am curious as to why I am able to re-declare the type of a type-paramertized argument to a scala function like this:
// original
def ident[T](z:T) = z
def echo[T](x:T) = {
ident(x)
}
echo("hi")
Which behaves exactly the same as this:
// modified with what seems to be a useless re-specification of the original type
def ident[T](z:T) = z
def echo[T](x:T) = {
ident(x:T) // <<< --- we specify type 'T' here, but not in the orig
}
echo("hi")
What is this language construct called? Does it have a name? And are there circumstances in which it
would actually be useful?
It's called type ascription. It's similar to a type cast, but not quite. i.e. if the type is not compatible, there will be a compiler error. So in that it is also like a type-check. If you say x: T, you're telling the compiler you expect x to be a T. If x is a T, then it will be treated as precisely a T.
How is it useful? You can use it to up-cast a bottom-type like null:
ident(null: T)
Or simply up-cast some non-null object.
In the context of your question, the ascription does nothing. We already know x is a T. But if we try to do it with something else..
class Z
scala> def test[T](t: T): T = { val z = new Z; ident(z: T) }
<console>:9: error: type mismatch;
found : z.type (with underlying type Z)
required: T
def test[T](t: T): T = { val z = new Z; ident(z: T) }
^
I primarily use it for type-checking while debugging code, in order to get more refined error messages (i.e. make sure the types are what I think they are).
Some concrete examples:
scala> val x = 1: Short
x: Short = 1
scala> val x = 1: Long
x: Long = 1
scala> val l = Nil: List[Int]
l: List[Int] = List()

Scala expression evaluation

I'm intrigued by the following Scala compiler behavior. When i declare a function of type unit, but nevertheless provide as body a function that evaluate to an Int, the Scala compiler is ok with it.
def add(x:Int, y:Int) = x + y
def main(args: Array[String]): Unit = {add(args(0).toInt, args(0).toInt)}
While the same is not true with other type such in
def afunc: String = {1} //type mismatch; found : Int(1) required: String
Also if i write
def afunc: Unit = {1}
or
def main(args: Array[String]): Unit = {2 + 2} // Which is just like the first addition above
In both case i get the following warning:
a pure expression does nothing in statement position; you may be omitting necessary parentheses
In a sense there is 2 questions here. What is the difference between a function that return evaluate to an Int and the expression 2 + 2. Then why on earth, the compiler does not complain that a function that is suppose to evaluate to Unit, gets a body that evaluate to another type, as it would happens between other types.
Many thanks in advance,
Maatari
What is the difference between a function that return evaluate to an
Int and the expression 2 + 2.
A function that evaluates to an Int might have side effects
var a = 0
def fn: Int = {
a = a + 1
1
}
Every call to fn changes the value of a.
Then why on earth, the compiler does not complain that a function that
is suppose to evaluate to Unit, gets a body that evaluate to another
type, as it would happens between other types.
When you specify Unit as the return type the compiler does an implicit conversion from whatever value the function returns to Unit (there is only one Unit value as it is an object, you can think of it as the void type of Scala).
Unit is inferred as a return type for convenience. For example,
scala> val h = new collection.mutable.HashMap[String,String]
h: scala.collection.mutable.HashMap[String,String] = Map()
scala> h += "fish" -> "salmon"
res1: h.type = Map(fish -> salmon)
we see that the += method on mutable HashMaps returns the map.
But if you don't infer unit, then
def add(a: String, b: String): Unit = h += a -> b
doesn't work.
Which thing is worse--accidentally expecting a return value vs. demanding you explicitly return the most boring possible return value--depends on how functional your code is. If you have more than a few side-effects, not inferring Unit is rather painful.
A function with just the parentheses is mainly called for the side-effects. It may return a result, as it was common in the days of C or Java but in reality we don't care, cause we will not use it.
{} is equivalent to : Unit =, and the annotation of return type can be seen as a cast or an implicit conversion to match the type expected by the function.
Here is another example where this behavior occurs.
def add(a: Int, b:Int) : Double = a + b
add: (a: Int, b: Int)Double
scala> add(4,5)
res17: Double = 9.0
Thus it seems that every value can be transformed to unit.
scala> val a: Unit = 1:Unit
<console>:28: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
val a: Unit = 1:Unit
^
a: Unit = ()

Can't understand why `trait Hello[+A] { def test[B<:A] }` can't be compiled

I can understand why the following code can't be compiled:
trait Hello[+A] {
def test[B<:A](x: B)
}
Because:
val child: Hello[String] = new Hello[String] {
def test[B <: String](x: B) = x.substring(1)
}
val parent: Hello[Any] = child
parent.test(123) // child.test can't handle integer
But I can't understand well why the following code can't be compiled:
trait Hello[+A] {
def test[B<:A]
}
The difference is the later one doesn't have parameters, we can't pass any value to the test method.
Why compiler still think it's invalid?
When you trying doing it in repl, it says:
scala> trait Hello[+A] {
| def test[B<:A](x: B)
| }
<console>:8: error: covariant type A occurs in contravariant position in type <: A of type B
def test[B<:A](x: B)
^
Rightly so. Imagine if this was possible and you could:
val x:Hello[Dog] = new Hello[Dog]{..}
val y:Hello[Animal] = x
y.test(Cat)//Oops
About the parameters, what makes you think it makes it safe without any arguments. You could get the variable using say implicitly and do dangerous stuff which compiler will not stop you. Example:
def test[B<:A]:B = this

What is `class A[_]` useful for?

The types of symbols class A[_] or of def a[_](x: Any) have a type parameter that can't be referenced in the body, thus I don't see where it is useful for and why it compiles. If one tries to reference this type parameter, an error is thrown:
scala> class A[_] { type X = _ }
<console>:1: error: unbound wildcard type
class A[_] { type X = _ }
^
scala> def a[_](x: Any) { type X = _ }
<console>:1: error: unbound wildcard type
def a[_](x: Any) { type X = _ }
^
Can someone tell me if such a type has a use case in Scala? To be exact, I do not mean existential types or higher kinded types in type parameters, only those litte [_] which form the complete type parameter list.
Because I did not get the answers I expected, I brought this to scala-language.
I paste here the answer from Lars Hupel (so, all credits apply to him), which mostly explains what I wanted to know:
I'm going to give it a stab here. I think the use of the feature gets
clear when talking about type members.
Assume that you have to implement the following trait:
trait Function {
type Out[In]
def apply[In](x: In): Out[In]
}
This would be a (generic) function where the return type depends on
the input type. One example for an instance:
val someify = new Function {
type Out[In] = Option[In] def
apply[In](x: In) = Some(x)
}
someify(3) res0: Some[Int] = Some(3)
So far, so good. Now, how would you define a constant function?
val const0 = new Function {
type Out[In] = Int
def apply[In](x: In) = 0
}
const0(3) res1: const0.Out[Int] = 0
(The type const0.Out[Int] is equivalent to Int, but it isn't
printed that way.)
Note how the type parameter In isn't actually used. So, here's how
you could write it with _:
val const0 = new Function {
type Out[_] = Int
def apply[In](x: In) = 0
}
Think of _ in that case as a name for the type parameter which
cannot actually be referred to. It's a for a function on the type
level which doesn't care about the parameter, just like on value
level:
(_: Int) => 3 res4: Int => Int = <function1>
Except …
type Foo[_, _] = Int
<console>:7: error: _ is already defined as type _
type Foo[_, _] = Int
Compare that with:
(_: Int, _: String) => 3 res6: (Int, String) => Int = <function2>
So, in conclusion:
type F[_] = ConstType // when you have to implement a type member def
foo[_](...) // when you have to implement a generic method but don't
// actually refer to the type parameter (occurs very rarely)
The main thing you mentioned, class A[_], is completely symmetric to
that, except that there's no real use case.
Consider this:
trait FlyingDog[F[_]] { def swoosh[A, B](f: A => B, a: F[A]): F[B] }
Now assume you want to make an instance of FlyingDog for your plain
old class A.
new FlyingDog[A] { ... }
// error: A takes no type parameters, expected: one
// (aka 'kind mismatch')
There are two solutions:
Declare class A[_] instead. (Don't do that.)
Use a type lambda:
new FlyingDog[({ type λ[α] = A })#λ]
or even
new FlyingDog[({ type λ[_] = A })#λ]
I had some casual ideas about what it could mean here:
https://issues.scala-lang.org/browse/SI-5606
Besides the trivial use case, asking the compiler to make up a name because I really don't care (though maybe I'll name it later when I implement the class), this one still strikes me as useful:
Another use case is where a type param is deprecated because
improvements in type inference make it superfluous.
trait T[#deprecated("I'm free","2.11") _, B <: S[_]]
Then, hypothetically,
one could warn on usage of T[X, Y] but not T[_, Y].
Though it's not obvious whether the annotation would come before (value parameter-style) or after (annotation on type style).
[Edit: "why it compiles": case class Foo[_](i: Int) still crashes nicely on 2.9.2]
The underscore in Scala indicates an existential type, i.e. an unknown type parameter, which has two main usage:
It is used for methods which do not care about the type parameter
It is used for methods where you want to express that one type parameter is a type constructor.
A type constructor is basically something that needs a type parameter to construct a concrete type. For example you can take the following signature.
def strangeStuff[CC[_], B, A](b:B, f: B=>A): CC[A]
This is a function that for some CC[_] , for example a List[_], creates a List[A] starting from a B and a function B=>A.
Why would that be useful? Well it turns out that if you use that mechanism together with implicits and typeclasses, you can get what is called ad-hoc polymorphism thanks to the compiler reasoning.
Imagine for example you have some higher-kinded type: Container[_] with a hierarchy of concrete implementations: BeautifulContainer[_], BigContainer[_], SmallContainer[_]. To build a container you need a
trait ContainerBuilder[A[_]<:Container[_],B] {
def build(b:B):A[B]
}
So basically a ContainerBuilder is something that for a specific type of container A[_] can build an A[B] using a B.
While would that be useful ? Well you can imagine that you might have a function defined somewhere else like the following:
def myMethod(b:B)(implicit containerBuilder:ContainerBuilder[A[_],B]):A[B] = containerBuilder.build(b)
And then in your code you might do:
val b = new B()
val bigContainer:BigContainer[B] = myMethod(b)
val beautifulContainer:BeautifulContainer[B] = myMethod(b)
In fact, the compiler will use the required return type of myMethod to look for an implicit which satisfies the required type constraints and will throw a compile error if there is no ContainerBuilder which meets the required constraints available implicitely.
That's useful when you deal with instances of parametrized types without caring of the type parameter.
trait Something[A] {
def stringify: String
}
class Foo extends Something[Bar] {
def stringify = "hop"
}
object App {
def useSomething(thing: Something[_]) :String = {
thing.stringify
}
}