Chris Bedford
Chris Bedford

Reputation: 2692

Advantages of declaring a method with a paramaterized type argument vs declaring the argument as Any?

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

Answers (1)

Tim Destan
Tim Destan

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

Related Questions