Reputation: 2692
I recently ran across this example, which prints "[7]"
class Decorator(left: String, right: String) {
def layout[A](x: A) = left + x.toString() + right
}
def apply(f: Int => String, v: Int) = f(v)
val decorator = new Decorator("[", "]")
println(apply(decorator.layout, 7))
It would also be possible to declare Decorator
like this:
class Decorator(left: String, right: String) {
def layout(x: Any) = left + x.toString() + right
}
I'm curious to know what are the advantages of the first approach?
Upvotes: 0
Views: 80
Reputation: 2028
In the specific example you gave there's not much difference, since the only thing you do with the value is call the method toString
on it, which is defined on Any
, and so is available to any value in Scala.
Often times, however, you may want to save that data and use it later. Let's say we have a custom type called Cat
:
case class Cat(name: String) {
def speak() = print(s"Meow, my name is $name.\n")
}
We may want to store a list of cats, and still be able to get the cats out of the list later and treat them as cats. The List[A]
class allows us to do this. Notice that is has a type parameter A
, which will allow it to remember the type of things it holds and return them with the correct type later. For example, we can write a function to make all the cats in our list speak.
def processCats(cats: List[Cat]) =
cats.foreach((cat:Cat) => cat.speak)
This is possible because the variable cat
inside the foreach
has type Cat
, so we can call Cat
's methods.
If List
were not generic, the variable cat would not be able to have type Cat
, and we wouldn't be able to use it as such without a runtime cast. List
doesn't actually work like this but we can simulate it:
type NonGenericList = List[Any]
def nonGenericProcessCats(cats: NonGenericList) =
cats.foreach((catAsAny:Any) => {
val cat = catAsAny.asInstanceOf[Cat]
cat.speak
})
This time, the variable catAsAny
in the foreach
has type Any
. We can convert it to a Cat
using asInstanceOf
, but it's now up to us to remember the type, and if we remember wrong, the cast will fail at runtime, crashing our program. With generics, the compiler can keep track of the correct type for us.
Upvotes: 2