I have something like the following...
class Base {
def doSomething = {...}
}
class B extends Base{
val text = "foo"
...
}
class C extends Base{
val value = "bar"
}
I would like a method that accepts any class that extends Base but keeps its extended properties. I tried this...
def myMethod[A extends Base](obj: A): Unit{
...
}
But this didn't work. How do I create a method that allows this?
The concept that you are looking for is that of an upper type bound. The standard notation for the subtyping relation is <:. This exact notation is also used in the Scala syntax for expressing type bounds:
// upper type bound, `A` must be subtype of `U`,
// analogous to Java's "A extends U"
def foo[A <: U]: Unit = ???
// lower type bound, `A` must be supertype of `L`,
// analogous to Java's "A super L"
def bar[A >: L]: Unit = ???
// Both upper and lower bounds simultaneously:
def baz[A >: U <: L]: Unit = ???
In your case, A should be subtype of Base, i.e. it should be bounded by Base from above: A <: Base
def myMethod[A <: Base](obj: A): Unit{
...
}
Another important difference to keep in mind when coming from Java is that in Scala, you have both the possibility for use-site variance, as well as declaration-site variance.
Related
[ I was unable to explain the problem with less verbosity. The core of the issue is that the compiler infers an underscore (_) type. In particular, [_ >: SomeType <: SomeOtherType]. I am clueless about when, how and why that is possible ]
As a scala exercise, I am trying to encode a vector of elements with a given size.
As a necessary step, I started by copying an existing encoding of natural numbers:
sealed trait Natural extends Product with Serializable {
def +(that: Natural): Natural
}
case object Zero extends Natural {
override def +(that: Natural): Natural = that
}
final case class Suc[N <: Natural](n: N) extends Natural {
override def +(that: Natural): Natural = Suc(n + that)
}
I believe the following diagram is a faithful portrayal of the type relation:
I then attempted to model a vector parameterized by a type on the elements and another type on size. To explain the problem though, I assumed a vector of ints and parameterized only the size of the vector :
import shapeless.=:!=
sealed trait Vector[+Size <: Natural] extends Product with Serializable {
def head: Int
def tail: Vector[Natural]
def plus[OtherSize >: Size <: Natural]
(that: Vector[OtherSize])
(implicit ev: OtherSize =:!= Natural): Vector[OtherSize]
}
case object VectorNil extends Vector[Zero.type] {
override def head: Nothing = throw new Exception("Boom!")
override def tail: Vector[Zero.type] = throw new Exception("Boom")
override def plus[OtherSize >: Zero.type <: Natural]
(that: Vector[OtherSize])
(implicit ev: =:!=[OtherSize, Natural]): Vector[OtherSize] = this
}
final case class VectorCons[N <: Natural](
head: Int,
tail: Vector[N]
) extends Vector[Suc[N]] {
override def plus[OtherSize >: Suc[N] <: Natural]
(that: Vector[OtherSize])
(implicit ev: =:!=[OtherSize, Natural]): Vector[OtherSize] = that
}
Notice that VectorCons[N] is actually a Vector of size Suc[N]. (extends Vector[Suc[N]]).
Method plus should add the elements of two vectors of the same size. I wanted to raise to the type level the verification that you can only sum vectors of the same size.
Notice that the conjunction of the type bounds OtherSize >: Size <: Natural with the implicit evidence should achieve that (see similar example at the bottom), but:
val foo = VectorCons(1, VectorCons(2, VectorNil))
//type -> VectorCons[Suc[Zero.type]]
// note that foo is (can be viewed) as Vector[Suc[Suc[Zero.type]], i.e
// a vector of 2 elements
val bar = VectorCons(3, VectorNil)
//type -> VectorCons[Zero.type]
val baz = foo.plus(bar)
//type -> Vector[Suc[_ >: Suc[Zero.type] with Zero.type <: Natural]] !! How is this possible ?? !!
to my frustration, baz compiles just fine!! The shapeless type constrain doesn't work; well, because OtherSize really is different from Natural; particularly, it is Suc[_ >: Suc[Zero.type] with Zero.type <: Natural].
So, I am very much confused with the type of baz! This is what allows the constraint to be bypassed.
What did the compiler infer for the type of baz/bar?
Is that an existential type ?
Is the compiler allowed to infer such things?
Is that not undesirable behavior ?
At this point, I am not concerned whether or not this is the correct encoding for a vector. Just wanted to understand how can the compiler infer that type for baz ?
p.s
1 - I am aware the return that on the implementation of method plus on VectorCons does not achieve what the plus semantics implies, but that is not important for the question.
###### Extra #######
I suspect this weird (at least for me) behavior has something to to with the natural numbers. The following code works fine!! :
[Disregard the absurd semantics of the code]
sealed trait Animal extends Product with Serializable
case class Dog() extends Animal
case class Cow() extends Animal
case object NoBox extends Animal //Not important
and,
trait Vector[+A <: Animal] {
def head: A
def plus[That >: A <: Animal]
(that: Vector[That])
(implicit ev: =:!=[That, Animal]): Vector[That]
}
case object Nil extends Vector[NoBox.type] {
def head: Nothing = throw new NoSuchElementException("Boom!")
override def plus[That >: NoBox.type <: Animal]
(that: Vector[That])(implicit ev: =:!=[That, Animal]): Vector[That] = this
}
case class Cons[A <: Animal](head: A) extends Vector[A] {
override def plus[That >: A <: Animal]
(that: Vector[That])(implicit ev: =:!=[That, Animal]): Vector[That] = that
}
whereby:
val foo = Cons(Dog())
val bar = Cons(Cow())
// Compiles
val baz = foo.plus(foo)
val baz2 = bar.plus(bar)
// Does not compile (what I would expect)
val baz3 = bar.plus(foo)
val baz4 = foo.plus(bar)
Thank you for your input,
I have these 2 implicits
trait A[T] {
val name: String
}
trait B
object A {
implicit def product[T <: Product] = new A[T] {
override val name: String = "product"
}
implicit def childOfB[T <: Product with B] = new A[T] {
override val name: String = "child of B"
}
}
and if I try to find an implicit instance of A[C] where C is
case class C() extends B
childOfB will be selected.
I know it is logical but why does this happen? I cannot find it documented anywhere.
Scala Language Specification says:
If there are several eligible arguments which match the implicit
parameter's type, a most specific one will be chosen using the rules
of static overloading resolution.
Overloading resolution has a notion of one symbol being more specific than other. Precise, general definition of specificity is quite complex (as you can see in the specification linked above) but in your case it boils down to the fact that childOfB covers strictly a subset of types covered by product and therefore is more specific.
Specification says
If there are several eligible arguments which match the implicit
parameter's type, a most specific one will be chosen using the rules
of static overloading resolution.
To extend #ghik's answer, from Programmming in Scala,
To be more precise, one implicit conversion is more specific than another if one of the following applies:
The argument of the former is a subtype of the latter's
Both conversions are methods, and the enclosing class of the former extends the enclosing class of the latter
My guess is that "argument" in that quote refers also to type parameters, as is sugggested by
object A {
implicit def A2Z[T <: A] = new Z[T] {println("A")}
implicit def B2Z[T <: B] = new Z[T] {println("B")}
}
trait A
trait B extends A
trait Z[T]
def aMethod[T <: A](implicit o: Z[T]) = ()
implicit val a: A = new A {}
aMethod // prints B even though we started with an A
In Scala,
What is the relationship between parameterized class with different type?
For example,
class A[T]
What is the relationship between A[Int] (or A[String]) and A?
and what is the relationship between A[Int] and A[String] ?
I want to know, because I would like to do something like
case class A[T](v: T) { def print = println(v) }
def iter(s: Seq[A[???]]) = s.map(print) // What is the proper annotation of '???'
iter(Seq(A(1), A("Hello")) // 1 Hello
What is the relationship between A[Int] and A?
A is a type constructor of kind * → *, and A[Int] is one of the possible results of apply a type (Int) to the type constructor A.
What is the relationship between A[Int] and A[String]?
The least upper bound between these two types is A[_ >: String with Int], which can only be instantiated to A[Any] since it's the only super class of String and Int.
What is the proper annotation of '???'
In your example that would be Any, or a type parameter you could add to your def iter that would itself be instantiated to Any.
Types are related using Variance.
To answer your question, Java's wildcards equivalent in Scala is Existential types. So you can specify something like this:
def iter(s: Seq[A[_]]) = s.map(_.print)
which is equivalent to:
def iter(s: Seq[A[T] forSome {type T}]) = s.map(_.print)
You can also specify bounds like below:
def iter(s: Seq[A[_ <: CharSequence]]) = s.map(_.print)
println(iter(Seq(A[StringBuilder](new StringBuilder("Test")), A[String]("Hello"))))
[Explicit type specified in constructors to avoid implicit conversion to required type CharSequence].
Note that the following would not compile though:
def iter(s: Seq[A[CharSequence]]) = s.map(_.print)
println(iter(Seq(A[StringBuilder](new StringBuilder("Test")), A[String]("Hello"))))
This is where variance specification in class would help:
case class A[+T](v: T) {
def print = v
}
def iter(s: Seq[A[CharSequence]]) = s.map(_.print)
println(iter(Seq(A[StringBuilder](new StringBuilder("Test")), A[String]("Hello"))))
I have the simplified situation:
abstract sealed trait Top
class A[T] extends Top
class B[T] extends Top
class Typeclass[T]
implicit def a[T] = new Typeclass[A[T]]
implicit def b[T] = new Typeclass[B[T]]
Now I have a Map[String, Top] and want to use an operation on all values in the map that require the presence of an instance of Typeclass to be available in the context. This will not compile as the concrete types of the values in the map are not visible from its type and I can therefore not set a context bound for them.
Is there a way to tell the compiler that in fact there will always be an instance available? In this example this is given as there are implicit functions to generate those instances for every concrete subtype of Top.
Or is the only solution to use a HList and recurse over its type requiring all the instances to be in context?
I recommend using some variation on this adaptation of Oleg's Existentials as universals in this sort of situation ... pack the the type class instance along with the value it's the instance for,
abstract sealed trait Top
class A[T] extends Top
class B[T] extends Top
class Typeclass[T]
implicit def a[T] = new Typeclass[A[T]]
implicit def b[T] = new Typeclass[B[T]]
trait Pack {
type T <: Top
val top: T
implicit val tc: Typeclass[T]
}
object Pack {
def apply[T0 <: Top](t0: T0)(implicit tc0: Typeclass[T0]): Pack =
new Pack { type T = T0 ; val top = t0 ; val tc = tc0 }
}
val m = Map("a" -> Pack(new A[Int]), "b" -> Pack(new B[Double]))
def foo[T: Typeclass](t: T): Unit = ()
def bar(m: Map[String, Pack], k: String): Unit =
m.get(k).map { pack =>
import pack._ // imports T, top and implicit tc
foo(top) // instance available for call of foo
}
bar(m, "a")
As discussed in comment it would be more convenient to have the typeclass defined on Top, and it might be done with pattern matching.
supposing part of the definition of the typeclass is
def f[T](t: T): FResult[T],
and you have the corresponding implentations
def fOnA[T](t: A[T]): FResult[A[T]] = ...
def fOnB[T](t: B[T]): FResult[B[T]] = ...
Then you can define
def fOnT(t: Top) : FResult[Top] = t match {
case a: A[_] => fOnA(a)
// provided an FResult[A[T]] is an FResult[Top],
// or some conversion is possible
case b: B[_] => fOnB(b)
}
If is both legal and safe to call a generic method, such as fOnA[T] with an existential (a matching A[_])
However, it might be difficult to convince the compiler that the parameter you pass to f or the result you get are ok, given the reduced information of the existential. If so, please post the signatures you need.
I have a generic trait MappingPath, invariant regarding it's type parameters:
trait MappingPath[X<:AnyMapping, Y<:AnyMapping]
and an interface of a factory for it:
trait Pathfinder[X, Y] {
def apply(fun :X=>Y) :MappingPath[_<:AnyMapping,_<:AnyMapping]
def get(fun :X=>Y) :Option[MappingPath[_<:AnyMapping, _<:AnyMapping]]
}
I start a skeleton implementation which works for a single mapping:
class MappingPathfinder[M<:AnyMapping, X, Y] extends Pathfinder[X, Y] {
override def apply(fun :X=>Y) :MappingPath[M, _<:AnyMapping] = ???
override def get(fun :X=>Y) :Option[MappingPath[M, _<:AnyMapping]] = ???
}
which produces a compile error complaining that MappingPathfinder.apply overrides nothing and doesn't implement Pathfinder.apply. What's interesting, replacing M with _<:AnyMapping in apply's return type makes it compile, and no complaints are made regarding similar get method.
What's going on? I use scala 2.11.5.
EDIT:
I was able to circumvene my problem by adding explicit existantial annotations:
//Pathfinder
def apply(fun :X=>Y) :MappingPath[A, B] forSome { type A<:AnyMapping; type B<:AnyMapping }
//MappingPathfinder
def apply(fun :X=>Y) :MappingPath[A, B] forSome { type A>:M<:M; type B<:AnyMapping }
It seems to work, i.e
I can do:
(p :MappingPath[_<:AnyMapping, M]) ++ mappingPathfinder(f),
where ++ requires a path starting with the exact same type as this ends. It looks a bit silly and certainly confusing though.
Not an answer, but your use case can be simplified to:
trait Higher[U]
trait Super {
def foo: Higher[_]
}
trait Sub[M] {
override def foo: Higher[M] // error: method foo overrides nothing
}
Instead of existential types, I would use a type member:
trait Super {
type U
def foo: Higher[U]
}
trait Sub[M] {
type U = M
}
I think the difference is that in the case of the existential type, you only specify that the type parameter returned has some upper bound, but not necessarily that it is always the same type; whereas in my second example, type U means this will eventually be one specific type, and you can only refine a specific type. You can make upper bounds more precise:
trait Upper
trait A {
type U <: Upper
}
trait Specific extends Upper
trait B extends A {
type U <: Specific // type is "overridden"
}
If it's possible, I would avoid existential types, and your case seems a perfect fit for such avoidance. Most of the time, existential types are only needed for Java interop.