F-bounded existential quantification - scala

I came across the existential quantification for F-bounded types while trying to understand scala's type system.
Let A be a type
trait A[F <: A[F]] { self: F => }
where F is the F-bounded self-type of A.
And B some subtype of A
case class B() extends A[B]
If I try to declare a List of A with existential quantification
val a: List[T] forSome { type T <: A[T] }
I get an error when assigning a a List of B. For some reason scala infers the type List[A[Nothing]].
val a: List[T] forSome { type T <: A[T] } = List(B()) // type mismatch
When applying the simplification rule 4 (as described in the scala-spec) the covariant occurrence of T may be replaced by the upper bound (here: A[T])
val b: List[A[T]] forSome { type T <: A[T] } = List(B())
Both examples should be equivalent (if I have not misunderstood something), but the simplified one works just fine. Furthermore the following is also correct and should be equivalent:
val c: List[T forSome { type T <: A[T] }] = List(B())
But for some reason the type of c and the type of b are not equal.
So my question is: Is this a bug of the scala compiler or did I misunderstand something crucial?
Edit: Is my assumption correct, that the types of c and b are not equal, because the existential quantification in c does not see the covariant occurrence of T?

Related

Scala - overriding type-member with bounds

I have the following problem with hierarchy of traits in Scala code:
First of all, I have a basic trait MyTrait[A] with such definition:
trait MyTrait[A] {
def v1: A
}
It is then followed by a definition of a trait Base with a type-member:
trait Base[A] {
type T <: MyTrait[A]
val baseV: T
}
And, at last, a trait Gen which overrides Base's type member.
trait Gen[A, X <: MyTrait[A]] extends Base[A] {
type T = X
}
The problem is that in the Gen trait it seems that bounds of the type-member are lost. This can be proven by following tests:
Compiles:
trait Test1 {
val x: Base[_]
println(x.baseV.v1)
}
Doesn't compile (value v1 is not a member of Test2.this.x.T):
trait Test2 {
val x: Gen[_, _]
println(x.baseV.v1)
}
I would like to know whether it's a limitation of the language or there is a workaround it. Questions on similar topics on stackowerflow (1, 2) appear to be focusing on different aspects than mine and I am genuinely at a loss because I can't find much information about such behavior in Scala.
Scala code template of this question can be found on scastie
This works:
trait Test2 {
val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
println(x.baseV.v1)
}
I believe the issue is that
Gen[_, _]
Has to mean
Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]
Which is the same as
Gen[A, X] forSome { type A; type X }
That is, even though the bounds on Gen say that X <: MyTrait[A], the wildcards do not inherit that bound. You can see a similar problem here:
trait Data { def data: String }
trait Box[A <: Data] { def data: A }
def unbox(b: Box[_]): String = b.data.data // nope; the wildcard is not <: Data
We can add the bounds to the wildcards explicitly. However, because the bound on the second wildcard depends on the first one, we are forced to use the extended forSome syntax for the existential, so we can name A and use it twice.
Gen[A, _ <: MyTrait[A]] forSome { type A }
And I opted to just put everything in the existential clause, which is equivalent:
Gen[A, X] forSome { type A; type X <: MyTrait[A] }
You can also use
Gen[_, _ <: MyTrait[_]]
but this is not equivalent, as it doesn't relate the left and right parameters. If Gen[A, _] contained an A in addition to a MyTrait[A], then using x: Gen[_, _ <: MyTrait[_]] would render the "bare" value and the "wrapped" value with incompatible types.

Two related existential type parameters

Let's take this example code:
trait DataProcessor[D] {
def computeData(): D
}
case class DataItem[D, P <: DataProcessor[D]](processor: P, data: D)
def computeDataFromItems(items: Set[DataItem[_, _]]) = items collectFirst {
case DataItem(s: DataProcessor[_], d) =>
s.computeData()
}
When compiled with Scala 2.11, it yield this error:
Error:(8, 77) type arguments [_$1,_$2] do not conform to class DataItem's type
parameter bounds [D,P <: TwoExistentials.DataProcessor[D]]
def computeDataFromItems(items: Set[DataItem[_, _]]) = items collectFirst {
It seems that the collectFirst method needs some more type information, that is not contained in the pair of existential types of the DataItem class.
Is there a chance to give more specific types to the method's arguments, something like:
def computeDataFromItems(items: Set[DataItem[D, P] forSome { type D, type P <: DataProcessor[D] }])
which unfortunately doesn't compile?
Otherwise, is there a way to allow for a class with two related type parameters to be used in collections, in a type-safe manner?
By the way, I have already considered using shapeless, instead of existential types. But I am looking for an implementation with classical Scala collections.
This should compile (replaced , with ;):
def computeDataFromItems(items: Set[DataItem[D, P] forSome { type D; type P <: DataProcessor[D] }])

Why invariant generic type parameterized with subclass of upper bounds fails to conform?

Given:
class Invar[T]
trait ExtendsAnyref extends AnyRef
def f(a: Invar[ExtendsAnyref]) = {}
The following is erroneous
scala> val x: Function1[Invar[_ <: AnyRef], Unit] = f
<console>:13: error: type mismatch;
found : Invar[ExtendsAnyref] => Unit
required: Invar[_ <: AnyRef] => Unit
val x: Function1[Invar[_ <: AnyRef], Unit] = f
^
Why?
I understand that in Scala, generic types have by
default nonvariant subtyping. Thus, in the context of this example, instances of Invar with different type parameters would never be in a subtype relationship with each other. So an Invar[ExtendsAnyref] would not be usable as a Invar[AnyRef].
But I am confused about the meaning of _ <: AnyRef which I understood to mean "some type below AnyRef in the type hierarchy." ExtendsAnyref is some type below AnyRef in the type hierarchy, so I would expect Invar[ExtendsAnyref] to conform to Invar[_ <: AnyRef].
I understand that function objects are contravariant in their input-parameter types, but since I use Invar[_ <: AnyRef] rather than Invar[AnyRef] I understood, apparently incorrectly, the use of the upper bounds would have the meaning "Invar parameterized with Anyref or any extension thereof."
What am I missing?
When you write
val x: Function1[Invar[_ <: AnyRef], Unit] = ...
it means x must accept any Invar[_ <: AnyRef]. That is, it must accept Invar[AnyRef], Invar[String], etc. f obviously doesn't: it only accepts Invar[ExtendsAnyref].
In other words, you need to combine your last two paragraphs: because functions are contravariant in argument types, for Function1[Invar[ExtendsAnyref], Unit] to conform to Function1[Invar[_ <: AnyRef], Unit] you'd need Invar[_ <: AnyRef] to conform to Invar[ExtendsAnyref], not vice versa.
If you
want a function that takes Invar parameterized with any subclass of AnyRef
this can be written as Function1[Invar[A], Unit] forSome { type A <: AnyRef }. However, I don't believe there is anything useful you could do with an object of this type, because 1) the only thing you can do with a function is to apply it to an argument, but 2) you don't know what arguments this function accepts.

Scala: type inference of generic and it's type argument

Lets assume I have instance of arbitrary one-argument generic class (I'll use List in demonstration but this can me any other generic).
I'd like to write generic function that can take instances (c) and be able to understand what generic class (A) and what type argument (B) produced the class (C) of that instance.
I've come up with something like this (body of the function is not really relevant but demonstrates that C conforms to A[B]):
def foo[C <: A[B], A[_], B](c: C) {
val x: A[B] = c
}
... and it compiles if you invoke it like this:
foo[List[Int], List, Int](List.empty[Int])
... but compilation fails with error if I omit explicit type arguments and rely on inference:
foo(List.empty[Int])
The error I get is:
Error:Error:line (125)inferred kinds of the type arguments (List[Int],List[Int],Nothing) do not conform to the expected kinds of the type parameters (type C,type A,type B).
List[Int]'s type parameters do not match type A's expected parameters:
class List has one type parameter, but type A has one
foo(List.empty[Int])
^
Error:Error:line (125)type mismatch;
found : List[Int]
required: C
foo(List.empty[Int])
^
As you can see Scala's type inference cannot infer the types correctly in this case (seems like it's guess is List[Int] instead of List for 2nd argument and Nothing instead of Int for 3rd).
I assume that type bounds for foo I've come up with are not precise/correct enough, so my question is how could I implement it, so Scala could infer arguments?
Note: if it helps, the assumption that all potential generics (As) inherit/conform some common ancestor can be made. For example, that A can be any collection inherited from Seq.
Note: the example described in this question is synthetic and is a distilled part of the bigger problem I am trying to solve.
This is a known limitation of current Scala's type inference for type constructors. Defining the type of formal parameter c as C only collects type constraints for C (and indirectly to A) but not B. In other words List[Int] <: C => { List[Int] <: C <: Any, C <: A[_] <: Any }.
There is a pretty simple translation that allows to guide type inference for such cases. In your case it is:
def foo[C[_] <: A[_], A[_], B](c: A[B]) { val x: A[B] = c }
Same semantics, just slightly different type signature.
In addition to hubertp answer, you can fix you function by removing obsolete (in you example) type variable C, e.g:
def foo[A[_], B](c: A[B]) {
val x: A[B] = c
}
In this case scalac would infer A[_] as List and B as Int.
Update (according to the comment).
If you need an evidence that C is subtype of A[B], then use implicit:
def foo[A[_], B, C](c: C)(implicit ev: C <:< A[B]) = {
val x: A[B] = c
}
Then it won't compile this:
scala> foo[List, String, List[Int]](List.empty[Int])
<console>:9: error: Cannot prove that List[Int] <:< List[String].
foo[List, String, List[Int]](List.empty[Int])

Scala: F-Bounded Polymorphism Woes

Assume the existence of the following types and method:
trait X[A <: X[A]]
case class C extends X[C]
def m(x: PartialFunction[X[_], Boolean])
I want to be able to create a PartialFunction to be passed into m.
A first attempt would be to write
val f: PartialFunction[X[_], Boolean] = {
case c: C => true
}
m(f)
This fails with type arguments [_$1] do not conform to trait X's type parameter bounds [A <: X[A]]. So, it seems we have to constraint X's type parameters.
A second attempt:
val f: PartialFunction[{type A <: X[A]}, Boolean] = {
case c: C => true
}
m(f)
This fails on the application of m because PartialFunction[AnyRef{type A <: X[this.A]},Boolean] <: PartialFunction[X[_],Boolean] is false.
Is there any way not involving casting that actually satisfies the compiler both on the definition of the partial function and on the application of m?
I'm not sure what exactly you want, but since you are using an existential type (in disguise of the _ syntax), this is how you can make that work:
val f: PartialFunction[X[A] forSome {type A <: X[A]}, Boolean] = {
case c : C => true
}
The _ syntax isn't good enough here, since you need to give the existential type the right upper bound. That is only possible with the more explicit forSome syntax.
What I find surprising, though, is that Scala accepts the declaration
def m(x: PartialFunction[X[_], Boolean])
in the first place. It seems weird that it even considers X[_] a well-formed type. This is short for X[A] forSome {type A <: Any}, which should not be a valid application of X, because it does not conform to the parameter bounds.
Not sure if that's what you wanted to achieve, but this is the working sequence:
trait X[A <: X[A]]
case class C extends X[C]
def m[T<:X[T]](x: PartialFunction[X[T], Boolean]) = print("yahoo!")
scala> def f[T<:X[T]]:PartialFunction[X[T], Boolean] = {
| case c: C => true
| }
f: [T <: X[T]]=> PartialFunction[X[T],Boolean]
scala> m(f)
yahoo!