Type equality in Scala - scala

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.

Related

T <: A, return T method

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 {}
}

Why class <:<[-From, +To] needs to extends (From => To) in scala standard library?

i am looking into scala's type level programming and have got some knowledge about it.But i have no idea why class <:< needs to extend from (From => To),i wrote the following code in REPL .
trait <:<[-T, +U] // just 'plain' generic trait
// an implicit object will looked up by compiler
implicit def implicitAgent[A]: <:<[A, A] = new <:<[A,A] {}
def myFunc[T,U](one:T, two:U)(implicit ev: T <:< U): Unit = {
println(one, two)
class Base {
override def toString: String = "base"
}
class Derived extends Base {
override def toString: String = "Derived"
}
myFunc(new Derived, new Base)
and it works and prints:
(Derived,base)
So my question is what's the class <:<'s design decision?why it needs to extends From => To ?
Because that way implicit ev: T <:< U also acts as an implicit conversion from T to U that can automatically upcast any value of type T to type U.
With <:< defined in Predef:
scala> trait Foo
defined trait Foo
scala> def myFunc[T](t: T)(implicit ev: T <:< Foo): Foo = t
myFunc: [T](t: T)(implicit ev: T <:< Foo)Foo
With your <:< :
scala> trait <:<[-T, +U]
defined trait $less$colon$less
scala> implicit def implicitAgent[A]: <:<[A, A] = new <:<[A,A] {}
implicitAgent: [A]=> A <:< A
scala> def myFunc[T](t: T)(implicit ev: T <:< Foo): Foo = t
<console>:14: error: type mismatch;
found : T
required: Foo
def myFunc[T](t: T)(implicit ev: T <:< Foo): Foo = t
^
Once you have a proof that a value is an instance of U (i.e. its type T is a subtype of type U) it's very likely that you will want to use that value as an instance of U, otherwise why did you need the proof in the first place? If <:< is a function you can do that automatically.

Resolve implicit parameter from super type

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)

Why do I need an explicit type argument list 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

Missing class manifest for Array of abstract type member

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)
}