here is some sample code:
trait A
trait B extends A
def test[T <: A](): T = {
new B {}
}
but I get an compile error:
type mismatch;
found : B
required: T
new B {}
how to make it working ?
( but without doing asInstanceOf[T] at the end )
thanks!
The signature of your method
def test[T <: A](): T
promises that for any type T that is a subtype of A you return a value of this type T. And then you returned a value of type B. You violated the signature (there are many subtypes of A, not only B).
For example you can try a type class (in this way you say that you return a value of T not for any T <: A at all but for any T <: A that can be handled by the type class MakeT)
def test[T <: A]()(implicit makeT: MakeT[T]): T = makeT.makeT()
trait MakeT[T] { // or MakeT[+T]
def makeT(): T
}
object MakeT {
implicit val bMakeT: MakeT[B] = () => new B {}
// or implicit def bMakeT[T >: B]: MakeT[T] = () => new B {}
}
test[B]().isInstanceOf[B] // true
In the situation described by #LuisMiguelMejíaSuárez in his comment
trait C extends A
you'll have
// test[C]() // doesn't compile, could not find implicit value for parameter makeT: MakeT[C]
Regarding generic return type see also
Why can't I return a concrete subtype of A if a generic subtype of A is declared as return parameter?
Type mismatch on abstract type used in pattern matching
Or you can use standard type classes =:=, <:<
def test[T <: A]()(implicit ev: B =:= T): T = {
new B {}
}
(not implicit ev: T =:= B)
or
def test[T <: A]()(implicit ev: B <:< T): T = {
new B {}
}
Related
Is it possible to resolve an implicit parameter for a type B if an implicit is defined for its super type A?
Here is an example :
I have an Enumerable typeclass :
trait Enumerable[A] {
def name(a: A): String
def list: List[A]
//... other methods
}
object Enumeration {
def name[A, T >: A](a: A)(implicit ev: Enumerable[T]) = ev.name(a)
def list[T](implicit ev: Enumerable[T]) = ev.list
// ...
}
Then I define an instance of enumerable :
sealed trait Season
case object Winter extends Season
case object Spring extends Season
case object Summer extends Season
case object Fall extends Season
implicit val seasonEnumerable = new Enumerable[Season] {
override def list: List[Season] = List(Winter, Spring, Summer, Fall)
}
// working :
Enumeration.name(Winter: Season) shouldBe "winter"
// faling :
Enumeration.name(Winter) shouldBe "winter"
Enumeration.name(Winter) is failing if I don't tell scalac that Winter is a Season. I've specified that the implicit parameter in the 'name' method signature is a supertype of A, but it's not sufficient...
Is there a better way to do this?
Eduardo's answer explains why the version with [A, T >: A] doesn't work. But there is a simpler solution to the problem than he gives: instead of introducing T infer as a type parameter, introduce it by an existential type:
def name[A](a: A)(implicit ev: Enumerable[T >: A] forSome { type T }) = ev.name(a)
Or, using a shorthand,
def name[A](a: A)(implicit ev: Enumerable[_ >: A]) = ev.name(a)
Then the compiler only has to decide what T is when looking for ev.
This is a common inconvenience whenever you need type-dependent types to be inferred. Your method
def name[A, T >: A](a: A)(implicit ev: Enumerable[T])
when called on Winter, first A will be inferred to Winter.type and then T to be A, as it conforms to that bound and there are no more constraints on it at that point. Then of course the compiler won't find an instance of Enumerable[Winter.type].
There's an easy solution with type members though:
trait AnyEnumerable {
type E
def name[A <: E](a: A): String
def list: List[E]
}
object Enumeration {
def name[A](a: A)(implicit ev: AnyEnumerable { type E >: A }) = ev.name(a)
def list[T](implicit ev: AnyEnumerable { type E = T }) = ev.list
// ...
}
// an implicit for `Season`
implicit val seasonEnumerable: AnyEnumerable { type E = Season } =
new AnyEnumerable {
type E = Season
def name[A <: Season](a: A): String = a.toString
def list: List[Season] = List(Winter, Spring, Summer, Fall)
}
// compiles!
val zzz = Enumeration.name(Winter)
My scenario is like:
trait A {
type B
def foo(b: B)
}
trait C[D <: A] {
val d: D
def createB(): D#B
def bar() {
d.foo(createB)
}
}
In REPL, it complains
<console>:24: error: type mismatch;
found : D#B
required: C.this.d.B
a.bar(createB())
What's wrong with this ? And (if possible at all) how to correct this code ?
D#B is a type projection, and is not the same as d.B. You have a type mismatch because in foo, Bactually meant this.B, which as said is not the same as D#B (the latter being more general).
Informally, you can think of D#Bas representing any possible type that the abstract type B can take for any instance of D, while d.B is the type of B for the specific instance d.
See What does the `#` operator mean in Scala? and What is meant by Scala's path-dependent types? for some context.
One way to make it compile it is by changing createB's return type to d.B:
def createB(): d.B
However in many cases such a solution is too restrictive because you are tied to the specific instance d, which might not be what you had in mind.
Another solution is then to replace the abstract type with a type parameter (though it is more verbose):
trait A[B] {
def foo(b: B)
}
trait C[B, D <: A[B]] {
val d: D
def createB(): B
def bar() {
d.foo(createB)
}
}
Update given this answer I'm not sure whether this should be considered a bug or not
This is a bug: SI-4377. An explicit type ascription yields
trait C[D <: A] {
val d: D
def createB(): D#B
def bar() {
(d:D).foo(createB)
// [error] found : D#B
// [error] required: _3.B where val _3: D
}
}
which looks like the implementation leaking. There's a workaround which involves casting to an intersection type (dangerous, casting is wrong etc; see my other answer here)
trait A {
type B
def foo(b: B)
}
case object A {
type is[A0 <: A] = A0 {
type B = A0#B
}
def is[A0 <: A](a: A0): is[A0] = a.asInstanceOf[is[A0]]
}
trait C[D <: A] {
val d: D
def createB(): D#B
def bar() {
A.is(d).foo(createB) // use it here!
}
}
I am writing a generic FSM library:
import scala.annotation.tailrec
trait State {
def isAcceptState: Boolean
}
trait FSM[T <: FSM[T, A, S], -A, +S <: State] { this: T =>
def state: S
def resume(input: A): T
}
object FSM {
#tailrec
def resumeUntilAccept[T <: FSM[T, A, S], A, S <: State](fsm: T, inputs: Iterator[A]): T = {
if (inputs.hasNext) {
val input = inputs.next
val newFSM = fsm.resume(input)
if (newFSM.state.isAcceptState) {
newFSM
} else {
resumeUntilAccept[T, A, S](newFSM, inputs) // THIS LINE OF CODE
}
} else {
throw new Exception("not enough inputs")
}
}
}
If I remove the type argument list on the line marked // THIS LINE OF CODE, I get the following error:
Main.scala:22: error: inferred type arguments [T,A,Nothing] do not conform to method resumeUntilAccept's type parameter bounds [T <: FSM[T,A,S],A,S <: State]
resumeUntilAccept(newFSM, inputs)
^
Why is Nothing inferred instead of S? And even then, why does it not conform? Nothing is clearly a subtype of State.
It is limitation of Scala type inference for type constructors, see SI-2712.
You can help compiler by changing type of argument to fsm: FSM[T, A, S]. The following simplified snippet slightly differs from original, but at least it compiles.
trait State
trait FSM[T <: FSM[T, A, S], -A, +S <: State]
object FSM {
def resumeUntilAccept[T <: FSM[T, A, S], A, S <: State](fsm: FSM[T, A, S], inputs: Iterator[A]): T = {
val newFSM: T = ???
resumeUntilAccept(newFSM, inputs)
}
}
I think because type S is not inferred from arguments until FSM is known. So compiler can't compare these S's. "Nothing" not conform to "unknown S" because of same reason.
trait Z[X]
scala> def aaa[A <: Z[B] ,B](a: A):A = aaa(a)
inferred type arguments [A,Nothing] do not conform
scala> def aaa[A <: Z[B], B](a: A):A = aaa[A, B](a)
aaa: [A <: Z[B], B](a: A)A
or even
scala> def aaa[A <: Z[B], B](a: Z[B]):A = aaa(a)
aaa: [A <: Z[B], B](a: Z[B])A
Here is a little snippet of code:
class Foo[A] {
def foo[B](param: SomeClass[B]) {
//
}
}
Now, inside foo, how do I:
1) verify if B is the same type as A?
2) verify if B is a subtype of A?
You need implicit type evidences, <:< for subtype check and =:= for same type check. See the answers for this question.
As a side note, generalized type constraints aren't actually necessary:
class Foo[A] {
def foo_subParam[B <: A](param: SomeClass[B]) {...}
def foo_supParam[B >: A](param: SomeClass[B]) {...}
def foo_eqParam[B >: A <: A](param: SomeClass[B]) {...}
def foo_subMyType[Dummy >: MyType <: A] {...}
def foo_supMyType[Dummy >: A <: MyType] {...}
def foo_eqMyType[Dummy1 >: MyType <: A, Dummy2 >: A <: MyType] {...}
}
In fact, I prefer this way, because it both slightly improves type inference and guarantees that no extraneous runtime data is used.
1) verify if B is the same type as A?
class Foo[A] {
def foo(param: SomeClass[A]) = ???
}
// or
class Foo[A] {
def foo[B](param: SomeClass[B])(implicit ev: A =:= B) = ???
}
2) verify if B is a subtype of A?
class Foo[A] {
def foo[B <: A](param: SomeClass[B]) = ???
}
// or
class Foo[A] {
def foo[B](param: SomeClass[B])(implicit ev: B <:< A) = ???
}
In your case, you do not need generalized type constraints (i.e. =:=, <:<). They're required when you need to add a constraint on the type parameter that is defined elsewhere, not on the method.
e.g. To ensure A is a String:
class Foo[A] {
def regularMethod = ???
def stringSpecificMethod(implicit ev: A =:= String) = ???
}
Here you cannot enforce the type constraint without a generalized type constraint.
I am looking for recommendations of providing a class manifest in an array instantiation. I have refactored this code (which compiles fine):
trait Ref[A]
trait Struct[A] {
val arr = new Array[Ref[A]](1)
}
to this:
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A]
}
trait Struct[S <: Sys[S], A] {
val arr = new Array[S#R[A]](1)
}
This fails with message "cannot find class manifest for element type S#R[A]"
So how would I solve this?
Your problem is that Array being invariant in its type parameter, requires a precise type argument. Your definition of type R in Sys is only providing an upper bound.
You can fix the problem at the definition site by replacing the upper bound on R with an equality,
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] = Ref[Self, A] // '=' not '<:'
}
trait Struct[S <: Sys[S], A] {
val arr = new Array[S#R[A]](1) // OK
}
Alternatively, if you'd prefer to leave R[A] open in Sys you can specify the equality constraint at the use site via a refinement, like so,
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A] // Back to an upper bound
}
trait Struct[S <: Sys[S] { type R[A] = Ref[S, A] }, A] {
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// Assert the equality via a refinement
val arr = new Array[S#R[A]](1) // OK
}
If you can't pin down type R in either of these ways, then you have no option but to provide the ClassManifest explicitly yourself,
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A]
}
trait Struct[S <: Sys[S], A] {
implicit val rM : ClassManifest[S#R[A]] // Provided manifest later ...
val arr = new Array[S#R[A]](1) // OK
}
class SomeSys extends Sys[SomeSys] {
type R[A] = Ref[SomeSys, A]
}
val s = new Struct[SomeSys, Int] {
val rM = implicitly[ClassManifest[SomeSys#R[Int]]]
// ^^^^^^^^^^^^^^
// Precise type known here
}
Which of these to pick depends very much on your larger context.
I could come up with one solution that involves a simple indirection:
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A]
def newRefArray[A](size: Int): Array[Self#R[A]]
}
trait Struct[S <: Sys[S], A] {
def sys: S
val arr = sys.newRefArray[A](1)
}