Matching type constraints in Scala fails - scala

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]]

Related

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[_])

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.

Is it possible to create a generic type T[A <: C[U], B <: C[U], U] that can be used as T[A, B]?

I have the following case class:
case class <*>[Q <: Quantity[T], R <: Quantity[T], T](value: T)
extends Quantity[T]
I would like to use it as such:
type Area[T] = Length[T] <*> Length[T]
However, I get an error saying that <*> expects three parameters and I’ve given only two. I would like it to work like this:
type Area[T] = <*>[Length[T], Length[T], T]
I tried the following but it gave me an error:
trait Quantity[T] {
type Value = T
def value: T
}
case class <*>[Q <: Quantity[_],
R <: Quantity[_]](value: Q#Value)
(implicit eq: Q#Value =:= R#Value)
extends Quantity[Q#Value]
Error:(13, 110) illegal inheritance;
self-type <*>[Q,R] does not conform to Quantity[_$1]'s selftype Quantity[_$1]
case class <*>[Q <: Quantity[_],
R <: Quantity[_]](value: Q#Value)
(implicit eq: Q#Value =:= R#Value)
extends Quantity[Q#Value]
^
Is there a workaround for this? I don’t mind renaming the case classes if necessary, although I do want the nice infix syntax.
The problem is the Q#Value reference.
I'd suggest using an implicit to enforce your type constraints rather than trying to make existentials work:
sealed trait CanStar[Q, R]
// could include =:=-like values in CanStar if you like
object CanStar {
implicit def canStar[Q <: Quantity[T], R <: Quantity[T], T] =
new CanStar[Q, R]{}
}
sealed case class <*>[Q,R](value: Q)(implicit cs: CanStar[Q, R])
Then <*> is a two-parameter type as desired, but you can only ever instantiate Q <*> R with Q and R which are suitably related (because implicit CanStar[Q, R]s are only available for suitable Q and R).

Why does Scala compiler say that contravariant type A occurs in covariant position in type >: A <: Any of type B?

The compiler is telling me this can't be with a warning of: "contravariant type A occurs in covariant position in type >: A <: Any of type B." The warning is in the type parameter of the compose method. Logically the type definition makes sense to me. If the compiler has no qualms with andThen, why the problem with the converse?
trait Foo[-A]{
def compose[B >: A](t: Foo[B]): Foo[A] = t andThen this
def andThen[B <: A](t: Foo[B]): Foo[B]
}
All I need is an example where it breaks down. Then I'm happy.
As the error says, your variance annotation of A is wrong. You cannot use A in a return type which is a covariant position. Imagine you had another method in Foo which uses A in proper contravariant position (as an argument):
trait Foo[-A] {
...
def foo(a: A): Unit
}
Now you can see how this crashes:
Foo[-A] implies that Foo[X] <: Foo[Y] if X >: Y
a returned value may be a subtype of the declared return type
therefore, if -A was legal here, compose might return a Foo[A1] for some A1 >: A
say trait X and trait Y extends X { def bar() }
imagine a Foo[Y] where foo calls a.bar()
consequently it would break if compose was allowed to return Foo[X]
So for you example to compile, A must be invariant.

Kinds not conforming with type lambda

Having trouble with type "kinds":
trait Sys[ S <: Sys[S]]
trait Expr[S <: Sys[S], A]
trait Attr[S <: Sys[S], A[_]]
def test[ S <: Sys[S]]: Attr[S, ({type l[x<:Sys[x]]=Expr[x,Int]})#l] = ???
This fails with
error: kinds of the type arguments (S,[x <: Sys[x]]Expr[x,Int]) do not conform
to the expected kinds of the type parameters (type S,type A) in trait Attr.
[x <: Sys[x]]Expr[x,Int]'s type parameters do not match type A's expected parameters:
type x's bounds <: Sys[x] are stricter than type _'s declared bounds >: Nothing <: Any
def test[S <: Sys[S]]: Attr[S, ({type l[x<:Sys[x]]=Expr[x,Int]})#l] = ???
^
What's the problem with the declared bounds? Do I need to carry that cr*ppy partially applied type into the type constructor of trait Attr? And why? Can I fix this without touching the definition of Attr?
I do need the bounds in function test in order for the implementation to work, but I do not want to proliferate those bounds to the public interface Attr.
Note: If I use a type member (what I don't want), it works:
trait Attr[S <: Sys[S]] { type A[_]}
def test[ S <: Sys[S]]: Attr[S] { type A[S <: Sys[S]] = Expr[S, Int]} = ???
As you observed, you can't always mismatch bounds when providing a higher-kinded type argument. Interestingly, it is actually a variance issue:
class A
class B extends A
trait NeedsNeedsA[T[S <: A]]
trait NeedsNeedsB[T[S <: B]]
trait NeedsA[S <: A]
trait NeedsB[S <: B]
def x: NeedsNeedsA[NeedsB] // fails
def y: NeedsNeedsB[NeedsA] // works
which makes sense if you think of a higher-kinded type as a function on types, contravariant in its argument's bound.
Interestingly, in a structural type, which is on the surface a lot like subtyping, Scala does not give the same error:
def t: MemberNeedsA { type T[S <: B] }
def u: MemberNeedsB { type T[S <: A] }
the reason being that a structural type is sort of like an intersection:
def s: MemberNeedsA with MemberNeedsB
and it may be that that intersection cannot actually exist in nature, but Scala doesn't check that.
OK, but that's not so relevant to your question. Back to your question: I think you have a variance issue. You want test to give the caller back an Attr, and an Attr posseses a type function (A[_]), and you want to say, this Attr has a type function that requires a more specific argument. I think you can see why you shouldn't be allowed to do that -- it's the same reason you can't substitute a function requiring a more specific argument in place of one that would require a more general argument.
At this point I'm afraid the solution will have to depend on what you want Attr to be able to accomplish. You need to figure out why you need to restrict the type argument in some cases more than others. If it makes conceptual sense in your program that "some Attrs are more restrictive than others", you could define:
trait Attr[S <: Sys[S], B[Y <: B[Y]], A[X <: B[X]]]
def test[S <: Sys[S]]: Attr[S, Sys, L] = ...
But the solution will depend on what the restriction on A[_]'s argument is intended to mean.