background-image: url(../img/fp-tower/website-background.svg) class: center, middle, white .title[Generic functions
part 1] --- # List is a generic data structure .twenty-seven-left[
```scala List[Int] List[String] List[User] ``` ] .fifty-seven-right[
] --- # How to avoid duplication? .thirty-seven-left[
```scala def size(list: List[Int] ): Int def size(list: List[String]): Int def size(list: List[User] ): Int ``` ] .fifty-seven-right[
] --- # Generic function .thirty-seven-left[
```scala def size[A](list: List[A]): Int ```
```scala size(List(1, 4, 8, -3)) // res1: Int = 4 size(List("Hello", "World", "!")) // res2: Int = 3 ``` ] .fifty-seven-right[
] --- # Generic function .forty-two-left[
```scala def size[Elem](list: List[Elem]): Int ```
```scala size(List(1, 4, 8, -3)) // res3: Int = 4 size(List("Hello", "World", "!")) // res4: Int = 3 ``` ] .fifty-seven-right[
] --- # Generic function
```scala def map[A](list: List[A], update: A => A): List[A] ```
```scala map(List(1,2,3,4), (x: Int) => x + 1) // res5: List[Int] = List(2, 3, 4, 5) map(List("Hello", "World"), (x: String) => x.reverse) // res6: List[String] = List("olleH", "dlroW") ``` --- # Generic function
```scala def map[A](list: List[A], update: A => A): List[A] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map(users, (user: User) => user.name) // error: type mismatch; // found : MdocApp0.this.User => String // required: java.io.Serializable => java.io.Serializable // map(users, (user: User) => user.name) // ^^^^^^^^^^^^^^^^^^^^^^^^^ ``` --- # Generic function
```scala def map[A](list: List[A], update: A => A): List[A] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map[User](users, (user: User) => user.name) // error: type mismatch; // found : String // required: MdocApp0.this.User // map[User](users, (user: User) => user.name) // ^^^^^^^^^ ``` --- # Generic function
```scala def map[From, To](list: List[From], update: From => To): List[To] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map(users, (user: User) => user.name) // res10: List[String] = List("John", "Eda", "Bob") map(List(1,2,3,4), (x: Int) => x + 1) // res11: List[Int] = List(2, 3, 4, 5) ``` --- # Generic function
```scala def map[From, To](list: List[From], update: From => To): List[To] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map(users, user => user.name) // error: missing parameter type // map(users, user => user.name) // ^^^^ map(users, _.name) // error: missing parameter type for expanded // function ((
) => x$1.name) // map(users, _.name) // ^ ``` --- # Generic function
```scala def map[From, To](list: List[From])(update: From => To): List[To] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map(users)(user => user.name) // res14: List[String] = List("John", "Eda", "Bob") map(users)(_.name) // res15: List[String] = List("John", "Eda", "Bob") ``` --- # Generic function in Dotty/Scala 3
```scala def map[From, To](list: List[From], update: From => To): List[To] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map(users, user => user.name) // res16: List[String] = List("John", "Eda", "Bob") map(users, _.name) // res17: List[String] = List("John", "Eda", "Bob") ``` --- # All generic types are not data structure
```scala trait JsonDecoder[A]{ def decode(value: Json): A } case class Predicate[A](value: A => Boolean) ``` --- class: white background-image: url(../img/fp-tower/website-background.svg)
# .white[Summary]
.medium[ * Generic functions reduce code duplication * We can have several type parameters * We split parameters into different set
of parentheses to help type inference ] --- # Least Upper Bound (LUB)
.fifty-seven-left[ ```scala def map[A](list: List[A], update: A => A): List[A] ```
```scala map(users, (user: User) => user.name) // error: type mismatch; // found : MdocApp5.this.User => String // required: java.io.Serializable => java.io.Serializable // map(users, (user: User) => user.name) // ^^^^^^^^^^^^^^^^^^^^^^^^^ ``` ] .thirty-seven-right[
] --- # Generic functions in Dotty
```scala def map[A](list: List[A], update: A => A): List[A] ```
```scala val users = List(User("John", 23), User("Eda", 37), User("Bob", 18)) ``` ```scala map(users, (user: User) => user.name) // Type Mismatch Error: // map(users, (user: User) => user.name) // ^^^^^^^^^ // Found: (user.name : String) // Required: User ```