Reputation: 1916
Is the following expected behavior or bug in Scala?
CASE 1:
class X[T1, T2]
class XExt[T1, T2] extends X[T1, T2]
class Y[T[t1] <: X[t1, _]]
class YExt extends Y[XExt]
results in Error: XExt takes two type parameters, expected: one
class YExt extends Y[XExt]
^
But the following runs ok:
class X[T1, T2]
class XExt[T1, T2] extends X[T1, T2]
class Y[T[t1, t2] <: X[t1, t2]]
class YExt extends Y[XExt]
Minimizing the number of params could simplify code like type params: type T[t1] <: X[t1, _].
CASE 2:
class X[T1, T2]
class Y[T[t1, t2] <: X[t1, t2]]
class Z[T <: Y[_]]
results in Error: _$1 takes no type parameters, expected: two
class Z[T <: Y[_]]
^
But how to avoid defining Y parameters if i do not require them? Like in:
class X[T1, T2]
class Y[T <: X[_, _]]
class Z[T <: Y[_]]
CASE 3:
trait A[T]
trait B[T[t] <: A[t]]
trait AExt extends A[Int]
trait BExt extends B[AExt]
results in Error: AExt takes no type parameters, expected: one
trait BExt extends B[AExt]
^
But why compiler requests one parameter if it's already supplied? It seems a contradiction. And how to subclass B?
That behavior is observed in IntelliJ Scala plugin and Eclipse Scala IDE. So it's probably the Scala compiler functioning.
Upvotes: 0
Views: 2922
Reputation: 1916
The cause of misunderstanding is really in mixing the notion of abstract type and generic parameter. Erroneous assumption was that type parameters and generic parameters are equal in rules of constraints. See below. T1 and T2 of class Z are equivalent. But in ZExt they can be defined with class XExt1 and XExt2 which have different number of params. The second param of XExt2 is just ignored. What i expected is that implementing the same logic with generics will allow the same syntax. I.e. Z1 will accept XExt1 as well as XExt2 (like T1 and T2 in Z). But It accepts only XExt1. Placing XExt2 as param results in error.
And honestly still do not understand why not give generics the freedom of types. I.e. why not let XExt2 be the param of Z1, allowing compiler to infer XExt2 param types and just ignore it's second param.
class X[T1, T2]
class XExt1[T1] extends X[T1, Int]
class XExt2[T1, T2] extends X[T1, T2]
class Z {
type T1[t] <: X[t, _]
type T2[t] <: X[t, _]
}
class ZExt extends Z {
type T1[t] = XExt1[t]
type T2[t] = XExt2[t,_]
}
// But...
class Z1[T[t] <: X[t, _]]
class ZExt1 extends Z1[XExt1]
class ZExt2 extends Z1[XExt2] // Error: XExt2 takes two type parameters, expected: one
Answers on cases:
CASE 1:
Class that extends class Y should exactly meet the T[t] (with one param) that is, for example:
class X[T1, T2]
class XExt[T1] extends X[T1, Int]
class Y[T[t1] <: X[t1, _]]
class YExt extends Y[XExt]
CASE 2:
As @Ende Neu mentioned extra param that meets constraint T[t1,t2] of class Y does its job:
class X[T1, T2]
class Y[T[t1, t2] <: X[t1, t2]]
class Z[S[t1, t2] <: X[t1,t2], T <: Y[S]]
Unfortunately T[t1,t2] cant be described with underscore syntax as @samthebest suggests. Compiler warns with "Wrong top statement declaration":
class Z[T <: Y[_[_, _]]]
CASE 3:
The same problem as in CASE 1. AExt should have one param. For example:
trait A[T]
trait B[T[t] <: A[t]]
trait AExt[T] extends A[T]
trait BExt[T] extends B[AExt]
Upvotes: 0
Reputation: 31553
Case 1: you said Y
takes a type with 1 param, but you gave it a type with two.
Case 2: Similar, try Z[T <: Y[_[_,_]]]
Case 3: You said B
takes a type with 1 param, but you gave it a type with two.
No bug, problem lies between keyboard and chair. What are actually trying to do? I.e. give examples, including concrete implementations, then maybe people can help more.
Upvotes: 1