Scala type bounds & variance - scala

I am trying to get a better understanding of the following behaviour:
scala> class C[-A, +B <: A]
<console>:7: error: contravariant type A occurs in covariant position
in type >: Nothing <: A of type B
class C[-A, +B <: A]
^
However the following works:
scala> class C[-A, +B <% A]
defined class C
I can see that there could be issues from the variance of the bounding and bounded variables being opposite, though I have am not clear on what the specific problem is.
I am even less clear on why changing the type bound to a view bound makes things ok. In the absence of applicable implicit conversions I would expect the two definitions to be have largely the same effect. If anything I would expect a view bound to provide more opportunities for mischief.
For a bit of background I defining classes that are in some ways like functions, and I wanted to do something like
CompositeFunc[-A, +B <: C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D])
extends BaseFunc[A, D]
Arguably
CompositeFunc[-A, +B <% C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D])
extends BaseFunc[A, D]
is actually preferable, but I would still like to better understand what is going on here.

First the easy one:
class C[-A, +B <% A]
This is equivalent to
class C[-A, +B](implicit view: B => A)
Since view is not publically returned, it is not in a position which would constrain the variance of A or B. E.g.
class C[-A, +B](val view: B => A) // error: B in contravariant position in view
In other words, C[-A, +B <% A] is no different than C[-A, +B] in terms of constraints, the view argument doesn't change anything.
The upper bound case C[-A, +B <: A] I'm not sure about. The Scala Language Specification in ยง4.5 states
The variance position of the lower bound of a type declaration or type parameter is the opposite of the variance position of the type declaration or parameter.
The variance of B does not seem to be involved, but generally the upper bound must be covariant:
trait C[-A, B <: A] // contravariant type A occurs in covariant position
This must somehow produce a problem? But I couldn't come up with an example which proofs that this construction becomes unsound in a particular case....
As for the composed function, why not just
class Composite[-A, B, +C](g: A => B, h: B => C) extends (A => C) {
def apply(a: A) = h(g(a))
}
EDIT: For example:
import collection.LinearSeq
def compose[A](g: Traversable[A] => IndexedSeq[A], h: Traversable[A] => LinearSeq[A]) =
new Composite(g, h)

Related

Representing subtype relationship with <: and <:< in Scala

Generally, I use <: to represent a subtype relationship like A <: B, either as part of type parameter or as a type member. When going through some stuff, I came across this "<:<" representation. Found it in Predef.scala and surprisingly, it is defined as an abstract class.
Doc says that:
An instance of A <:< B witnesses that A is a subtype of B. Requiring an implicit argument of the type A <:< B encodes the generalized constraint A <: B.
Could some one please clarify what exactly is the difference between the two, given the fact that both represents the same "subtype" relationship (AFAIK). Also, please suggest their correct usage (I mean, where <:< is preferred over <:) ?
[A <: B] declares a type parameter, A, with a known property/restriction: it must be type B (an existing type) or a sub-type thereof.
class A // A and B are unrelated
class B
// these both compile
def f1[A <: B]() = ??? // A is the type parameter, not a reference to class A
def f2[B <: A]() = ??? // B is the type parameter, not a reference to class B
[A <:< B] is used to test existing types.
class B
class A extends B
// A and B must already exist and have this relationship or this won't compile
implicitly[A <:< B]

Type parameter bound not considered when generic type is used with unbounded wildcard

In my project, I have a constellation like this:
trait F
trait X[A <: F]
def test(x: X[_]): X[_ <: F] = x
Trait X has a type parameter with an upper bound of F. From my understanding, the types X[_] and X[_ <: F] should be equivalent. But scalac 2.12.5 complains that one is not assignable to the other.
$ scalac -Xscript test test.scala
test.scala:5: error: type mismatch;
found : this.X[_$1] where type _$1
required: this.X[_ <: this.F]
def test(x: X[_]): X[_ <: F] = x
^
I cannot think of a situation where this assignment is making a sound program unsound. What are the reasons that this assignment is rejected? Is there a way that allowing such an assignment (maybe in a more complex example) is problematic?
This assignment isn't really problematic, and the compiler even kind-of knows this, because the following implementation compiles without problems:
trait F
trait X[A <: F]
def test(x: X[_]): X[_ <: F] = x match { case q: X[t] => q }
If you give the type checker some slack by allowing it to infer more precise bounds for the type variable t, it will eventually figure out that t must be subtype of F, and then allow you to return the value q (which is the same as x) without complaining. It doesn't do this by default for some counter-intuitive reasons that probably have something to do with Java-wildcard interoperability.
(Undeleted again; My original guess didn't seem too far off, and given Dmytro Mitin's link, it doesn't even seem all that vague by comparison.)
i might be wrong, but it's enough to look at the definition of the function itself:
def test(x: X[_]): X[_ <: F] = x
the only information existential type gives is that there exists something. and with this signature you try to "narrow" the function result
put it in a practical way with an example. let's say you have smth like this:
def test(x: Option[_]): Option[_ <: String]
and then you call it passing inside Option[Int]. would you expect this assignment to be correct?
val result: Option[_ <: String] = test(Some(1): Option[_])

How to aid Scala in type inference?

Sometimes Scala has trouble inferring the types. The goal here is to understand why and try to help Scala to do better inference.
The problem is better explained with a simple example:
trait A
trait B
class G[Ao <: A, Bo <: B](a: Ao, b: Bo)
// This is my "complex" class with 3 type parameters
class X[Ao <: A, Bo <: B, Go <: G[Ao,Bo]](a: Ao, b: Bo, g: Go)
val a = new A{}
val b = new B{}
val g = new G(a,b)
Here the type of OO below is perfectly inferred:
class OO extends X(a,b,g) // Type of X[A,B,G[A,B]]
However, if we change one of the arguments to be an option (or any collection that is), and we provide an empty collection (or None) then inference doesn't work.
case class X[Ao <: A, Bo <: B, Go <: G[Ao,Bo]](a: Ao, b: List[Bo], g: Go)
class OO extends X(a,List(),g)
<console>:XX: error: inferred type arguments [A,Nothing,G[A,B]] do not conform to class X's type parameter bounds [Ao <: A,Bo <: B,Go <: G[Ao,Bo]]
class OO extends X(a,List(),g)
^
<console>:XX: error: type mismatch;
found : A
required: Ao
class OO extends X(a,List(),g)
^
<console>:XX: error: type mismatch;
found : G[A,B]
required: Go
class OO extends X(a,List(),g)
This can be fixed by explicitly passing all the parameters of OO like this:
class OO extends X[A,B,G[A,B]](a,List(),g)
The thing is, G already has its types, and from the definition of X we see that G takes the first two parameters of X, so if we know G we have everything we need to infer the parameters of X. Can I do something different to help Scala with the inference? I have a class that has much more parameters than X and now I always have to explicitly define them. I am trying to see if there is something I can do to help Scala successfully infer the types.
I guess you could use higher kinded types:
case class X[Ao <: A, Bo <: B, Go[GAo <: Ao, GBo <: Bo] <: G[GAo, GBo]](a: Ao, b: List[Bo], g: Go[Ao, Bo])
class OO extends X(a,List(),g)
or, if your type parameters are covariant:
case class G[+Ao <: A, +Bo <: B](a: Ao, b: Bo)
case class X[Ao <: A, Bo <: B, Go[_ <: Ao, _ <: Bo] <: G[Ao, Bo]](a: Ao, b: List[Bo], g: Go[Ao, Bo])
I know from experience that the scala compiler can't infer types from parameters of the same group when they depend on each other on "different levels" like in this example. A higher kinded type allows me to explicitly declare type bounds and help the compiler infer the right types.

Scala. Generic class declaration trouble

I have a trouble with class declaration in Scala:
class Class2[
A,
B <: Class2[A,B,C],
C <: Class3[A,C]
]
class Class3[
A,
C <: Class3[A,C]
]
class Class1[
A,
B <: Class2[A,B,C],
C <: Class3[A,C]
](obj : B) { ... }
It is correct declaration, but every time I want to create an instance of that class I need to specify parameters A and C by hand. Like:
val X = Class1[Type1, Type2, Type3](correct_object_of_Type2)
If I try val X = Class1(OBJ) it will lead to error ...types [Nothing, B, Nothing] do not conform to [A, B, C]...
Why doesn't Scala infer types A and C from B? And how to declare class for a Scala compiler so that it will be able to specify A, C by itself? Thanks
EDIT
I'm sorry for formulation, the original task is to correctly define Class1 like:
class Class2[
A,
B <: Class2[A,B,C],
C <: Class3[A,C]
]
class Class3[
A,
C <: Class2[A,C]
]
??class Class1(obj : Class2) { ... }??
... so that it will be correct to call val x = Class1(obj), where obj: Class2. When I try to define it as above, I'm getting error Class2 takes type parameters. Any ideas?
Sorry for inaccuracy.
It's possible to have the type parameters inferred by encoding the constraints as implicit parameters:
class Class2[X, Y, Z]
class Class3[X, y]
class Class1[A, B, C](obj: B)(implicit
evB: B <:< Class2[A, B, C],
evC: C <:< Class3[A, C]
)
And then:
scala> class Foo extends Class3[String, Foo]
defined class Foo
scala> class Bar extends Class2[String, Bar, Foo]
defined class Bar
scala> new Class1(new Bar)
res0: Class1[String,Bar,Foo] = Class1#ff5b51f
If you need to use instances of B or C as Class2[A, B, C] or Class3[A, C] in the definition of Class1, you can apply the appropriate evidence parameter (evB or evC) to them.
Your version doesn't work because Scala's type inference system is very limited. It will first solve for A and end up at Nothing, since the argument to the constructor doesn't have an A in it. Next it will try to solve for B and not be able to find a value that satisfies the constraint, since it's already decided A is Nothing.
So you have to decide whether type inference is worth an extra bit of complexity and runtime overhead. Sometimes it is, but in my experience when you have classes like this with relationships that are already fairly complex, it's usually not.

Matching type constraints in Scala fails

I am trying to create a map wrapper in Scala 2.9.2 with values that have a particular higher kinded type, and am wrestling with the type system. Here is a cut down version of the code to illustrate the problem:
trait A
trait B[C] {
def c: C
}
trait E[C <: B[C], D <: A]
case class MyMap[M <: A, L <: B[L], N[L, M]](map: Map[M, N[L, M]])
object MyMap {
def empty[M <: A, L <: B[L], N[L, M]] = MyMap(Map.empty[M, N[L, M]])
}
val myMap = MyMap.empty[A, T forSome { type T <: B[T] }, E]
when I try and compile this, the last statement fails with a compiler error, indicating that I am not matching type bounds. However to me it looks like I am, and perhaps that where I have N[L, M] and previously L <: B[L], it is not inferring that the L in N[L, M] is the same L <: B[L], and likewise for M. Error is as follows:
kinds of the type arguments (A,T forSome { type T <: B[T] },E) do not conform to the expected kinds of the type parameters (type M,type L,type N). E's type parameters do not match type N's expected parameters: type C's bounds >: Nothing <: B[C] are stricter than type L's declared bounds >: Nothing <: Any, type D's bounds >: Nothing <: A are stricter than type M's declared bounds >: Nothing <: Any
val myMap = MyMap.empty[A, T forSome { type T <: B[T] }, E]
Any advice gratefully received.
Thanks -
There is one problem with the second parameter and one with the third. I don't know about the second parameter, I'm not sure what may be allowed here with existentia. So this is just about the problem with the third parameter.
A bit of simpler code with the same error :
class A {}
class C[X <: A] {}
def f[X[_]] = 12
f[List]
res1: Int12
f[C]
error: kinds of the type arguments (C) do not conform to
the expected kinds of the type parameters (type X).
C's type parameters do not match type X's expected parameters:
type X's bounds >: Nothing <: A are stricter
than type _'s declared bounds >: Nothing < : Any
f[C]
^
Quite simply, method empty expects as third type parameter a generic type with two parameters and no restrictions. In the body of empty, you are allowed to write N[Int, String] or whatever. Type E, which has some constraints, is not compatible with this (note: I find writing N[L,M] rather than N[_, _], with L and M the name of the previous type parameters a bit misleading. Or maybe it suggests you don't really want a higher order type parameter).
If you write in the code above
def g[X[_ <: A]] = 13
then calling g[C] is ok (g[List] ok too, as it should, nothing wrong can happen there).
Similarly, your code would work (provided you pass a suitable second parameter) if empty was
Map.empty[M <: A, L <: B[L], N[X <: B[X], Y <: A]]