Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
|
fp2025:lab09 [2026/05/16 22:57] silviu created |
fp2025:lab09 [2026/05/21 18:08] (current) silviu |
||
|---|---|---|---|
| Line 6: | Line 6: | ||
| * get yourself familiar with covariance and contravariance | * get yourself familiar with covariance and contravariance | ||
| * see the benefits of using these concepts | * see the benefits of using these concepts | ||
| + | * understand bounded generics | ||
| - | *Introduction* | + | **Introduction** |
| - | When we define a generic type, for example ''Box[T]'', and we have a types ''Animal'' and ''Dog'' and ''Dog extends Animal'', the type ''Shelter[Dog]'' does not extend type ''Shelter[Animal]''. However, sometimes we would like to have a conversion in one direction or the other. For example, consider the following code: | + | When we define a generic type, for example ''Shelter[T]'', and we have a types ''Animal'' and ''Dog'' and ''Dog extends Animal'', the type ''Shelter[Dog]'' does not extend type ''Shelter[Animal]''. However, sometimes we would like to have a conversion in one direction or the other. For example, consider the following code: |
| <code scala> | <code scala> | ||
| Line 52: | Line 53: | ||
| </code> | </code> | ||
| - | **9.2.** Modify this type to use the correct variance: | + | **9.2.** Modify this type to use the correct variance to the generic parameter: |
| <code scala> | <code scala> | ||
| Line 92: | Line 93: | ||
| println(" -> No animals matched this criteria.") | println(" -> No animals matched this criteria.") | ||
| } else { | } else { | ||
| - | matches.foreach(animal => println(s" -> MATCH: ${animal.name}")) | + | println(s" -> There were ${matches.length} matches.") |
| } | } | ||
| } | } | ||
| </code> | </code> | ||
| - | **9.6.** Apply the ''crossJoinAndFilter'' method on every possible shelter-predicate combination from the previous exercises, note which ones compile and which none don't. | + | Notice the invariance of the generic parameter, it will come up in the last exercise. |
| + | |||
| + | **9.6.** Apply the ''crossJoinAndFilter'' method on every possible shelter-predicate combination from the previous exercises, note which ones compile and which ones don't. | ||
| **9.7.** Complete the following code and use the proper bound and use it on some shelter: | **9.7.** Complete the following code and use the proper bound and use it on some shelter: | ||
| Line 109: | Line 112: | ||
| - | **9.7.** Complete the following code and use the proper bound to implement it, start from a shelter for ''Corgi'' and then expand it by adding new types of residents: | + | **9.8.** Complete the following code and use the proper bound to implement it, start from a shelter for ''Corgi'' and then expand it by adding new types of residents: |
| <code scala> | <code scala> | ||
| Line 115: | Line 118: | ||
| def saveAnimal[???T???](newResident: T): Shelter[T] = { | def saveAnimal[???T???](newResident: T): Shelter[T] = { | ||
| - | //Create a new shelter by adding the new resident | + | // Returns a new Shelter[T] containing the old residents + the new resident |
| } | } | ||
| </code> | </code> | ||
| - | **9.8.** Apply the proper generic types to this function and test it, ''S'' is the type of residents in the shelter and ''P'' is the type to test in the predicate, chose the proper bound: | + | **9.9.** Apply the proper generic types to this function and test it, ''S'' is the type of residents in the shelter and ''P'' is the type to test in the predicate, chose the proper bound: |
| + | <code scala> | ||
| def safeCrossJoin[???](shelter: Shelter[S], predicate: Predicate[P]): Unit = { | def safeCrossJoin[???](shelter: Shelter[S], predicate: Predicate[P]): Unit = { | ||
| println(s"Safely filtering ${shelter.name}:") | println(s"Safely filtering ${shelter.name}:") | ||
| Line 129: | Line 133: | ||
| } | } | ||
| } | } | ||
| + | </code> | ||