I thought this was asked already, but, if so, the question isn't apparent in the "related" bar. So, here it is:
What is a View Bound?
A view bound was a mechanism introduced in Scala to enable the use of some type A
as if it were some type B
. The typical syntax is this:
def f[A <% B](a: A) = a.bMethod
In other words, A
should have an implicit conversion to B
available, so that one can call B
methods on an object of type A
. The most common usage of view bounds in the standard library (before Scala 2.8.0, anyway), is with Ordered
, like this:
def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b
Because one can convert A
into an Ordered[A]
, and because Ordered[A]
defines the method <(other: A): Boolean
, I can use the expression a < b
.
Please be aware that view bounds are deprecated, you should avoid them.
What is a Context Bound?
Context bounds were introduced in Scala 2.8.0, and are typically used with the so-called type class pattern, a pattern of code that emulates the functionality provided by Haskell type classes, though in a more verbose manner.
While a view bound can be used with simple types (for example, A <% String
), a context bound requires a parameterized type, such as Ordered[A]
above, but unlike String
.
A context bound describes an implicit value, instead of view bound's implicit conversion. It is used to declare that for some type A
, there is an implicit value of type B[A]
available. The syntax goes like this:
def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]
This is more confusing than the view bound because it is not immediately clear how to use it. The common example of usage in Scala is this:
def f[A : ClassManifest](n: Int) = new Array[A](n)
An Array
initialization on a parameterized type requires a ClassManifest
to be available, for arcane reasons related to type erasure and the non-erasure nature of arrays.
Another very common example in the library is a bit more complex:
def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
Here, implicitly
is used to retrive the implicit value we want, one of type Ordering[A]
, which class defines the method compare(a: A, b: A): Int
.
We'll see another way of doing this below.
How are View Bounds and Context Bounds implemented?
It shouldn't be surprising that both view bounds and context bounds are implemented with implicit parameters, given their definition. Actually, the syntax I showed are syntactic sugars for what really happens. See below how they de-sugar:
def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod
def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)
So, naturally, one can write them in their full syntax, which is specially useful for context bounds:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)
What are View Bounds used for?
View bounds are used mostly to take advantage of the pimp my library pattern, through which one "adds" methods to an existing class, in situations where you want to return the original type somehow. If you do not need to return that type in any way, then you do not need a view bound.
The classic example of view bound usage is handling Ordered
. Note that Int
is not Ordered
, for example, though there is an implicit conversion. The example previously given needs a view bound because it returns the non-converted type:
def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b
This example won't work without view bounds. However, if I were to return another type, then I don't need a view bound anymore:
def f[A](a: Ordered[A], b: A): Boolean = a < b
The conversion here (if needed) happens before I pass the parameter to f
, so f
doesn't need to know about it.
Besides Ordered
, the most common usage from the library is handling String
and Array
, which are Java classes, like they were Scala collections. For example:
def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b
If one tried to do this without view bounds, the return type of a String
would be a WrappedString
(Scala 2.8), and similarly for Array
.
The same thing happens even if the type is only used as a type parameter of the return type:
def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted
What are Context Bounds used for?
Context bounds are mainly used in what has become known as typeclass pattern, as a reference to Haskell's type classes. Basically, this pattern implements an alternative to inheritance by making functionality available through a sort of implicit adapter pattern.
The classic example is Scala 2.8's Ordering
, which replaced Ordered
throughout Scala's library. The usage is:
def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b
Though you'll usually see that written like this:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
import ord.mkOrderingOps
if (a < b) a else b
}
Which take advantage of some implicit conversions inside Ordering
that enable the traditional operator style. Another example in Scala 2.8 is the Numeric
:
def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)
A more complex example is the new collection usage of CanBuildFrom
, but there's already a very long answer about that, so I'll avoid it here. And, as mentioned before, there's the ClassManifest
usage, which is required to initialize new arrays without concrete types.
The context bound with the typeclass pattern is much more likely to be used by your own classes, as they enable separation of concerns, whereas view bounds can be avoided in your own code by good design (it is used mostly to get around someone else's design).
Though it has been possible for a long time, the use of context bounds has really taken off in 2010, and is now found to some degree in most of Scala's most important libraries and frameworks. The most extreme example of its usage, though, is the Scalaz library, which brings a lot of the power of Haskell to Scala. I recommend reading up on typeclass patterns to get more acquainted with all the ways in which it can be used.
EDIT
Related questions of interest:
Scala has a restriction on automatic conversions to add a method, which is that it won't apply more than one conversion in trying to find methods. For example:
class A(val n: Int)
class B(val m: Int, val n: Int)
class C(val m: Int, val n: Int, val o: Int) {
def total = m + n + o
}
// This demonstrates implicit conversion chaining restrictions
object T1 { // to make it easy to test on REPL
implicit def toA(n: Int): A = new A(n)
implicit def aToB(a: A): B = new B(a.n, a.n)
implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)
// won't work
println(5.total)
println(new A(5).total)
// works
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
}
EDIT: View bounds ('<%') are deprecated since Scala 2.11 https://issues.scala-lang.org/browse/SI-7629 (You can use type classes instead)
However, if an implicit definition requires an implicit parameter itself(View bound), Scala will look for additional implicit values for as long as needed. Continue from the last example:
// def m[A <% B](m: A) is the same thing as
// def m[A](m: A)(implicit ev: A => B)
object T2 {
implicit def toA(n: Int): A = new A(n)
implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)
// works
println(5.total)
println(new A(5).total)
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
}
"Magic!", you might say. Not so. Here is how the compiler would translate each one:
object T1Translated {
implicit def toA(n: Int): A = new A(n)
implicit def aToB(a: A): B = new B(a.n, a.n)
implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)
// Scala won't do this
println(bToC(aToB(toA(5))).total)
println(bToC(aToB(new A(5))).total)
// Just this
println(bToC(new B(5, 5)).total)
// No implicits required
println(new C(5, 5, 10).total)
}
object T2Translated {
implicit def toA(n: Int): A = new A(n)
implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)
// Scala does this
println(bToC(5)(x => aToB(x)(y => toA(y))).total)
println(bToC(new A(5))(x => aToB(x)(identity)).total)
println(bToC(new B(5, 5))(identity).total)
// no implicits required
println(new C(5, 5, 10).total)
}
So, while bToC
is being used as an implicit conversion, aToB
and toA
are being passed as implicit parameters, instead of being chained as implicit conversions.
EDIT
Related question of interest:
Best Answer
Types of Implicits
Implicits in Scala refers to either a value that can be passed "automatically", so to speak, or a conversion from one type to another that is made automatically.
Implicit Conversion
Speaking very briefly about the latter type, if one calls a method
m
on an objecto
of a classC
, and that class does not support methodm
, then Scala will look for an implicit conversion fromC
to something that does supportm
. A simple example would be the methodmap
onString
:String
does not support the methodmap
, butStringOps
does, and there's an implicit conversion fromString
toStringOps
available (seeimplicit def augmentString
onPredef
).Implicit Parameters
The other kind of implicit is the implicit parameter. These are passed to method calls like any other parameter, but the compiler tries to fill them in automatically. If it can't, it will complain. One can pass these parameters explicitly, which is how one uses
breakOut
, for example (see question aboutbreakOut
, on a day you are feeling up for a challenge).In this case, one has to declare the need for an implicit, such as the
foo
method declaration:View Bounds
There's one situation where an implicit is both an implicit conversion and an implicit parameter. For example:
The method
getIndex
can receive any object, as long as there is an implicit conversion available from its class toSeq[T]
. Because of that, I can pass aString
togetIndex
, and it will work.Behind the scenes, the compiler changes
seq.IndexOf(value)
toconv(seq).indexOf(value)
.This is so useful that there is syntactic sugar to write them. Using this syntactic sugar,
getIndex
can be defined like this:This syntactic sugar is described as a view bound, akin to an upper bound (
CC <: Seq[Int]
) or a lower bound (T >: Null
).Context Bounds
Another common pattern in implicit parameters is the type class pattern. This pattern enables the provision of common interfaces to classes which did not declare them. It can both serve as a bridge pattern -- gaining separation of concerns -- and as an adapter pattern.
The
Integral
class you mentioned is a classic example of type class pattern. Another example on Scala's standard library isOrdering
. There's a library that makes heavy use of this pattern, called Scalaz.This is an example of its use:
There is also syntactic sugar for it, called a context bound, which is made less useful by the need to refer to the implicit. A straight conversion of that method looks like this:
Context bounds are more useful when you just need to pass them to other methods that use them. For example, the method
sorted
onSeq
needs an implicitOrdering
. To create a methodreverseSort
, one could write:Because
Ordering[T]
was implicitly passed toreverseSort
, it can then pass it implicitly tosorted
.Where do Implicits come from?
When the compiler sees the need for an implicit, either because you are calling a method which does not exist on the object's class, or because you are calling a method that requires an implicit parameter, it will search for an implicit that will fit the need.
This search obey certain rules that define which implicits are visible and which are not. The following table showing where the compiler will search for implicits was taken from an excellent presentation about implicits by Josh Suereth, which I heartily recommend to anyone wanting to improve their Scala knowledge. It has been complemented since then with feedback and updates.
The implicits available under number 1 below has precedence over the ones under number 2. Other than that, 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 (see Scala Specification §6.26.3). More detailed information can be found in a question I link to at the end of this answer.
Same scope in other filesLet's give some examples for them:
Implicits Defined in Current Scope
Explicit Imports
Wildcard Imports
Same Scope in Other Files
Edit: It seems this does not have a different precedence. If you have some example that demonstrates a precedence distinction, please make a comment. Otherwise, don't rely on this one.
This is like the first example, but assuming the implicit definition is in a different file than its usage. See also how package objects might be used in to bring in implicits.
Companion Objects of a Type
There are two object companions of note here. First, the object companion of the "source" type is looked into. For instance, inside the object
Option
there is an implicit conversion toIterable
, so one can callIterable
methods onOption
, or passOption
to something expecting anIterable
. For example:That expression is translated by the compiler to
However,
List.flatMap
expects aTraversableOnce
, whichOption
is not. The compiler then looks insideOption
's object companion and finds the conversion toIterable
, which is aTraversableOnce
, making this expression correct.Second, the companion object of the expected type:
The method
sorted
takes an implicitOrdering
. In this case, it looks inside the objectOrdering
, companion to the classOrdering
, and finds an implicitOrdering[Int]
there.Note that companion objects of super classes are also looked into. For example:
This is how Scala found the implicit
Numeric[Int]
andNumeric[Long]
in your question, by the way, as they are found insideNumeric
, notIntegral
.Implicit Scope of an Argument's Type
If you have a method with an argument type
A
, then the implicit scope of typeA
will also be considered. By "implicit scope" I mean that all these rules will be applied recursively -- for example, the companion object ofA
will be searched for implicits, as per the rule above.Note that this does not mean the implicit scope of
A
will be searched for conversions of that parameter, but of the whole expression. For example:This is available since Scala 2.9.1.
Implicit Scope of Type Arguments
This is required to make the type class pattern really work. Consider
Ordering
, for instance: It comes with some implicits in its companion object, but you can't add stuff to it. So how can you make anOrdering
for your own class that is automatically found?Let's start with the implementation:
So, consider what happens when you call
As we saw, the method
sorted
expects anOrdering[A]
(actually, it expects anOrdering[B]
, whereB >: A
). There isn't any such thing insideOrdering
, and there is no "source" type on which to look. Obviously, it is finding it insideA
, which is a type argument ofOrdering
.This is also how various collection methods expecting
CanBuildFrom
work: the implicits are found inside companion objects to the type parameters ofCanBuildFrom
.Note:
Ordering
is defined astrait Ordering[T]
, whereT
is a type parameter. Previously, I said that Scala looked inside type parameters, which doesn't make much sense. The implicit looked for above isOrdering[A]
, whereA
is an actual type, not type parameter: it is a type argument toOrdering
. See section 7.2 of the Scala specification.This is available since Scala 2.8.0.
Outer Objects for Nested Types
I haven't actually seen examples of this. I'd be grateful if someone could share one. The principle is simple:
Other Dimensions
I'm pretty sure this was a joke, but this answer might not be up-to-date. So don't take this question as being the final arbiter of what is happening, and if you do noticed it has gotten out-of-date, please inform me so that I can fix it.
EDIT
Related questions of interest: