

Type Parameterization and Type System: Introduction
source link: https://blog.knoldus.com/type-parameterization-and-type-system-introduction/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Type Parameterization and Type System: Introduction
Reading Time: 3 minutes
Scala is a static type language, which means types are checked at compile time instead of runtime. Type System provides safety during the compile time because we are detecting the error beforehand as these can be a potential error at runtime. Type parameterization also called as generics combined with Scala’s type system.
We can write generic code so that we can reuse that code. Suppose, we want to add two decimal numbers. We’d make something like this:
object Addition extends App {
def sumFloat(number1:Float,number2:Float): Float = number1 + number2
sumFloat(3.2,2.3)
}
Further, requirement comes to add all value types, then we’d make something like this:
object Addition extends App {
def sumAnyVal(number1:AnyVal,number2:AnyVal): AnyVal =
(number1, number2) match {
case (number1: Int, number2: Int) => number1 + number2
case (number1: Float, number2: Float) => number1 + number2
case (number1: Double, number2: Double) => number1 + number2
case _ => throw RuntimeException
}
sumAnyVal(1,2)
sumAnyVal(3.2,2.3)
}
Further, requirement comes to add String as well i.e., concatenate the String inputs. Now the condition becomes to add decimal values, all value types and Strings as well. Then, we’d do something like this:
object Addition extends App {
def sumAny(number1:Any,number2:Any): Any =
(number1, number2) match {
case (number1: Int, number2: Int) => number1 + number2
case (number1: Float, number2: Float) => number1 + number2
case (number1: Double, number2: Double) => number1 + number2
case(number1: String, number2: String) => number1 + number2
case _ => throw new RuntimeException
}
sumAny(1,2)
sumAny(3.2,2.3)
sumAny("Hello","World")
}
Let’s say we call sumAny method as:
sumAny(new AnyRef, new AnyRef)
This will give the result as RuntimeException and that’s where the problem arises.
Exception in thread "main" java.lang.RuntimeException
To overcome this problem, type safety comes as a solution as it will tell at the compile time only that sumAny(new AnyRef, new AnyRef) will be a potential error, kindly handle it first.
object Addition extends App {
trait Adder[T] {
def sum(number1: T, number2: T): T
}
def sum[T](number1: T, number2: T)(implicit adder: Adder[T]): T =
adder.sum(number1, number2)
implicit val addString = new Adder[String] {
override def sum(word1: String, word2: String): String = word1 + word2
}
sum("Hello", "World")
}
Now if we call sum method as sum(new AnyRef, new AnyRef), it will result in an error at compile time only.
For more on type system, refer to Scala Documentation or The Scala Type System.
Type Parameterization
Type parameterization also called as generics combined with Scala’s type system. It provides the ability to write code which is more predictable during compile time rather than time.
It allows us to write generic classes and traits.
We can also make parameters and return type of method as generic. This leads to question where to make classes or traits generic and where does make parameters and return type generic?
If we declare the type parameter at class level, we assign the actual type upon construction and can’t change it later- all invocation of the methods present inside the generic class, will have to use the same type.
scala> trait Animal
defined trait Animal
scala> case class Dog() extends Animal
defined class Dog
scala> case class Cat() extends Animal
defined class Cat
scala> class Owner[A<: Animal]{
| def feed(a:A) = println("Feeding my pet")
| }
defined class Owner
Now, let’s create Cat and Dog object and make a call to feed method.
scala> val dog = Dog()
dog: Dog = Dog()
scala> val cat = Cat()
cat: Cat = Cat()
scala> val owner = new Owner[Dog]
owner: Owner[Dog] = Owner@4cf4d528
scala> owner.feed(dog)
Feeding my pet
Here, a single owner has a specific pet, so it is good to use type at class level.
If we use type parameter at the method level, we can assign a different type in each invocation of the method.
scala> class AnimalLover {
| def feed[A<: Animal](a:A) = println("Feeding street animals")
| }
defined class AnimalLover
scala> val dog = Dog()
dog: Dog = Dog()
scala> val cat = Cat()
cat: Cat = Cat()
scala> val animalLoverPerson = new Animal
Animal AnimalLover
scala> val animalLoverPerson = new AnimalLover
animalLoverPerson: AnimalLover = AnimalLover@657c8ad9
scala> animalLoverPerson.feed(dog)
Feeding street animals
scala> animalLoverPerson.feed(cat)
Feeding street animals
An animal lover person might feed both Dogs and Cats, so feed method must be parameterized, and in this use case there is no use in adding a parameter at class level.
Conclusion
Generics are a powerful way of abstraction and writing type safe code which is more compile time reliant rather than run time.
This is small introduction to Type System and Type Parameterization. Some of the advanced topics variance, bounds, higherkinded type will be discussed in the next write up.
References
Recommend
-
82
Table of contents : Default dynamic type text styles Use Accessbility Inspector to speed up testing different text size Adapting label to larger font size Detecting...
-
14
Normally, programming languages with typeclasses (aka traits) do not have subtyping polymorphism à la Java, like Haskell and Rust. By trait I mean “proper trait”, unlike Scala’s, which is just a composable version of Java
-
17
Simple Parameterization and Trivial Plans — Part 1 SentryOne eBooksIn these books, you will find useful, hand-picked articles that will help give insight into some of your most vexing perfo...
-
4
Parameter Data Types As mentioned in the first part of this series, one of the reasons it is better to explicitly parameterize is so you ha...
-
7
Execution Plans It’s more complicated than you might expect to tell from the information provided in execution plans if a SQL statement uses simple parameterization. It’s no surprise even highly experienced SQL Server users...
-
8
[ This series: Part 1 | Part 2...
-
3
Simple Parameterization and Trivial Plans — Part 5 [ This series: Part 1 |
-
4
PrettySize 0.3 release and a weakness in rust’s type system In which we discuss the limitations of rust's...
-
7
Simple Parameterization and Trivial Plans — Part 6 [ This series: Part 1 |
-
9
If you’re used to writing unit tests, you might already know that when you’re testing a function with parameters, you want to test it using many (or ideally, all) possible inputs. That is to ensure that the function is doing what we want for anyth...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK