I was looking at the documentation for PartialFunction in this link:
trait PartialFunction[-A, +B] extends (A) ⇒ B
Maybe someone can help clarify the significance of the plus and minus signs in the generic declaration?
Most Scala generic classes are collections, such as the immutable List, Queue, Set, Map, or their mutable equivalents, and Stack. Collections are containers of zero or more objects. We also have generic containers that aren't so obvious at first.
In Scala, forming a Generic Class is extremely analogous to the forming of generic classes in Java. The classes that takes a type just like a parameter are known to be Generic Classes in Scala. This classes takes a type like a parameter inside the square brackets i.e, [ ].
It means an abstract type member is defined (inside some context, e.g. a trait or class), so that concrete implementations of that context must define that type. However, there is a constraint that this type ( Currency ) must actually be a subtype of AbstractCurrency .
Scala is a statically typed programming language. This means the compiler determines the type of a variable at compile time. Type declaration is a Scala feature that enables us to declare our own types.
"+" and "-" mean covariant and contravariant types respectively. In short, it means that:
PartialFunction[-A1, +B1]
<: PartialFunction[-A2, +B2]
only if A1 :> A2
and B1 <: B2
, where <:
is a subtyping relationship.
"-" usually applied for input parameters, "+" for output - in C# they even use respective keywords in
and out
. There is also some more primitive generic variance support in Java built up on existential types - actually you can do it using _ <: SomeType
(covariance) or abstract type members type T <: SomeType
in Scala as well.
Without modifiers PartialFunction[A1, B1]
would have no direct relationship to a PartialFunction[A2, B2]
(in other words, it would be invariant).
P.S. There are also some restrictions applied to such types, like covariant("+") type can't be in contravariant position (you can only return it from a method) and vice-versa. This is done in order to support Liskov Substitution Principle and naturally understandable by "in"/"out" interpretation.
Also, it worth noting that A => B
(syntax sugar for Function1
) itself is using co-/contra-variance:
trait Function1 [-T1, +R] extends AnyRef
As those functions can be extended through sub-typing which makes them theoretically partial as well (though it’s not how Scala treats these) - even technically “total” FunctionN in Scala could be extended, redefined, return null and so on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With