Sergii Vorobei
Sergii Vorobei

Reputation: 1497

Scala type parameters in various places

I have just started learning scala and have some issues with general understanding of type parameters. Previously I learned Haskell, but in scala it seems very confusing to me. It is unclear for me where should I put type parameters (near class definition or function definition).

Consider the example:

class Person[A] {
  def sayName (name: A) = println(name)
}

Does it make sense to move type parameter from class to function?

class Person {
  def sayName[A] (name: A) = println(name)
}

Or I even can leave type parameter both in class and function and it will work. Does it make some big difference? Will the [A] parameters in function override same param from class definition?

And I can create the instance of Person or call a function without pointing the exact type.

val p = new Person();

So why is this for? Just in cases when I want smth generic? So it is unclear for me when and on which positions (class or function) should I put type parameters.

Upvotes: 4

Views: 6419

Answers (2)

Tzach Zohar
Tzach Zohar

Reputation: 37852

  • If you declare the type parameter at the class level, you assign the actual type upon construction, and can't change it later - all invocations of sayName on a given instance will have to use the same type.

  • If you declare the type parameter at the method level, you can assign a different type in each invocation of the method.

So - if an instance of the class should always apply to a single type - use class-level definition.

For example:

trait Animal
case class Dog() extends Animal
case class Cat() extends Animal

// A single owner has a *specific* pet, 
// so it makes sense to declare type at class level
class Owner[A <: Animal] {
  def feed(a: A) = ???
}

// A single RandomAnimalLover walking down the street, 
// might feed both Dogs and Cats - so their feed method must be parameterized, and there's no use in adding a parameter at the class level
class RandomAnimalLover {
  def feed[A <: Animal](a: A) = ???
}

val dog = Dog()
val cat = Cat()
val ownerA = new Owner[Dog]
val randomDude = new RandomAnimalLover

ownerA.feed(dog) // compiles
ownerA.feed(cat) // does not compile

randomDude.feed(dog) // compiles
randomDude.feed(cat) // compiles

Lastly, if you declare a type parameter both at the class level and at the method level - these are two separate parameters!

  • If they have different names, both can be used anywhere.
  • If they have the same name, the method-level parameter will shadow the class level parameter within the scope of that method's definition and implementation (but nowhere else in the class).

Upvotes: 9

jrjd
jrjd

Reputation: 475

What you want to achieve will dictate where to put the type parameter.

Type parameter in class definition

Put the type parameter in the class definition to make some attribute of your class generic. It could be a val, a class parameter or a function argument.

Type parameter in method definition

Put the type parameter in the class definition to allow your method to be called with a generic type.

Example

class Person[A](name: A) {
  def sayName = println(name)
  def sayFirstName(firstName: A) = println(firstName)
  def saySomething[B](thing: B) = println(s"$name says $thing")
}

// in console

scala> val p = new Person[String]("Barker")
p: Person[String] = Person@4f5a80a8

scala> p.sayName
Barker

scala> p.sayFirstName("John")
John

scala> p.sayFirstName(4)
<console>:14: error: type mismatch;
 found   : Int(4)
 required: String
   p.sayFirstName(4)
                  ^

scala> p.saySomething("hello")
Barker says hello

scala> p.saySomething(42)
Barker says 42

Method sayFirstName takes an argument the same type as name. I want name and firstName to have the same type, and I can enforce it this way.

Method saySomething has a new type parameter B. So the Person can say something of any type.

Side note

As you noted, you could also replace B by A and have the same behavior: the type argument in the method definition will override the one in the class definition. But this should be avoided for the sake of readability.

Upvotes: 1

Related Questions