Added new solutions for the last sections
This commit is contained in:
parent
296d6e3fe0
commit
334cf23a9c
|
@ -1,38 +1,4 @@
|
|||
## Type Checking (#1)
|
||||
|
||||
Modify `TypeCheck3.kt` by moving `rotate()` into `Shape` and returning `Shape`
|
||||
to an `interface`. Notice how `turn()` becomes much cleaner.
|
||||
|
||||
> Solution 1
|
||||
|
||||
```kotlin
|
||||
// TypeChecking/TypeCheckingSoln1.kt
|
||||
package typecheckingsoln1
|
||||
import atomictest.eq
|
||||
import typechecking.name
|
||||
|
||||
interface Shape {
|
||||
fun draw() = "${this.name}: Draw"
|
||||
fun rotate() = ""
|
||||
}
|
||||
|
||||
class Circle : Shape
|
||||
|
||||
class Square : Shape {
|
||||
override fun rotate() = "Square: Rotate"
|
||||
}
|
||||
|
||||
class Triangle : Shape {
|
||||
override fun rotate() = "Triangle: Rotate"
|
||||
}
|
||||
|
||||
fun turn(s: Shape) = s.rotate()
|
||||
|
||||
fun main() {
|
||||
val shapes = listOf(Circle(), Square())
|
||||
shapes.map { it.draw() } eq
|
||||
"[Circle: Draw, Square: Draw]"
|
||||
shapes.map { turn(it) } eq
|
||||
"[, Square: Rotate]"
|
||||
}
|
||||
```
|
||||
to an `interface`. Notice how `turn()` becomes much cleaner.
|
|
@ -1,10 +1,10 @@
|
|||
package typeCheckingExercise1
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestTypeCheckingExercise1 {
|
||||
@Test fun testSolution() {
|
||||
Assert.assertTrue("Tests not implemented for the task", false)
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -4,135 +4,4 @@ Add a `DecomposableBottle` to both `BeverageContainer2.kt` (remove `recycle()`)
|
|||
and `BeverageContainer3.kt`. `DecomposableBottle`'s recycling `String` is
|
||||
"Decomposition tank".
|
||||
|
||||
Notice the different experience between the two examples.
|
||||
|
||||
> Solution 2a
|
||||
|
||||
```kotlin
|
||||
// TypeChecking/TypeCheckingSoln2a.kt
|
||||
package typecheckingsoln2a
|
||||
import atomictest.eq
|
||||
|
||||
sealed class BeverageContainer {
|
||||
abstract fun open(): String
|
||||
abstract fun pour(): String
|
||||
}
|
||||
|
||||
sealed class Can : BeverageContainer() {
|
||||
override fun open() = "Pop Top"
|
||||
override fun pour() = "Can: Pour"
|
||||
}
|
||||
|
||||
class SteelCan : Can()
|
||||
class AluminumCan : Can()
|
||||
|
||||
sealed class Bottle : BeverageContainer() {
|
||||
override fun open() = "Remove Cap"
|
||||
override fun pour() = "Bottle: Pour"
|
||||
}
|
||||
|
||||
class GlassBottle : Bottle()
|
||||
sealed class PlasticBottle : Bottle()
|
||||
class PETBottle : PlasticBottle()
|
||||
class HDPEBottle : PlasticBottle()
|
||||
class DecomposableBottle : PlasticBottle()
|
||||
|
||||
fun BeverageContainer.recycle2() =
|
||||
when(this) {
|
||||
is Can -> when(this) {
|
||||
is SteelCan -> "Recycle Steel"
|
||||
is AluminumCan -> "Recycle Aluminum"
|
||||
}
|
||||
is Bottle -> when(this) {
|
||||
is GlassBottle -> "Recycle Glass"
|
||||
is PlasticBottle -> when(this) {
|
||||
is PETBottle -> "Recycle PET"
|
||||
is HDPEBottle -> "Recycle HDPE"
|
||||
is DecomposableBottle -> "Decomposition tank"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val refrigerator = listOf(
|
||||
SteelCan(), AluminumCan(),
|
||||
GlassBottle(),
|
||||
PETBottle(), HDPEBottle(),
|
||||
DecomposableBottle()
|
||||
)
|
||||
refrigerator.map { it.open() } eq
|
||||
"[Pop Top, Pop Top, Remove Cap, " +
|
||||
"Remove Cap, Remove Cap, Remove Cap]"
|
||||
refrigerator.map { it.recycle2() } eq
|
||||
"[Recycle Steel, Recycle Aluminum, " +
|
||||
"Recycle Glass, " +
|
||||
"Recycle PET, Recycle HDPE, " +
|
||||
"Decomposition tank]"
|
||||
}
|
||||
```
|
||||
|
||||
> Solution 2b
|
||||
|
||||
```kotlin
|
||||
// TypeChecking/TypeCheckingSoln2b.kt
|
||||
package typecheckingsoln2b
|
||||
import atomictest.eq
|
||||
import typechecking.name
|
||||
|
||||
interface BeverageContainer {
|
||||
fun open(): String
|
||||
fun pour() = "${this.name}: Pour"
|
||||
fun recycle(): String
|
||||
}
|
||||
|
||||
abstract class Can : BeverageContainer {
|
||||
override fun open() = "Pop Top"
|
||||
}
|
||||
|
||||
class SteelCan : Can() {
|
||||
override fun recycle() = "Recycle Steel"
|
||||
}
|
||||
|
||||
class AluminumCan : Can() {
|
||||
override fun recycle() = "Recycle Aluminum"
|
||||
}
|
||||
|
||||
abstract class Bottle : BeverageContainer {
|
||||
override fun open() = "Remove Cap"
|
||||
}
|
||||
|
||||
class GlassBottle : Bottle() {
|
||||
override fun recycle() = "Recycle Glass"
|
||||
}
|
||||
|
||||
abstract class PlasticBottle : Bottle()
|
||||
|
||||
class PETBottle : PlasticBottle() {
|
||||
override fun recycle() = "Recycle PET"
|
||||
}
|
||||
|
||||
class HDPEBottle : PlasticBottle() {
|
||||
override fun recycle() = "Recycle HDPE"
|
||||
}
|
||||
|
||||
class DecomposableBottle : PlasticBottle() {
|
||||
override fun recycle() = "Decomposition tank"
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val refrigerator = listOf(
|
||||
SteelCan(), AluminumCan(),
|
||||
GlassBottle(),
|
||||
PETBottle(), HDPEBottle(),
|
||||
DecomposableBottle()
|
||||
)
|
||||
refrigerator.map { it.open() } eq
|
||||
"[Pop Top, Pop Top, Remove Cap, " +
|
||||
"Remove Cap, Remove Cap, Remove Cap]"
|
||||
refrigerator.map { it.recycle() } eq
|
||||
"[Recycle Steel, Recycle Aluminum, " +
|
||||
"Recycle Glass, " +
|
||||
"Recycle PET, Recycle HDPE, " +
|
||||
"Decomposition tank]"
|
||||
}
|
||||
```
|
||||
Notice the different experience between the two examples.
|
|
@ -1,10 +1,10 @@
|
|||
package typeCheckingExercise2
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestTypeCheckingExercise2 {
|
||||
@Test fun testSolution() {
|
||||
Assert.assertTrue("Tests not implemented for the task", false)
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -5,73 +5,4 @@ modifications to other components). Change `basic()` to use a `when`
|
|||
expression.
|
||||
|
||||
What does this gain you, since the `else` clauses in the `when` expressions
|
||||
still make sense?
|
||||
|
||||
> Solution 3
|
||||
|
||||
```kotlin
|
||||
// TypeChecking/TypeCheckingSoln3.kt
|
||||
package typecheckingsoln3
|
||||
import atomictest.eq
|
||||
import typechecking.name
|
||||
|
||||
sealed class Insect {
|
||||
open fun walk() = "${this.name}: walk"
|
||||
open fun fly() = "${this.name}: fly"
|
||||
}
|
||||
|
||||
class HouseFly : Insect()
|
||||
|
||||
class Flea : Insect() {
|
||||
override fun fly() =
|
||||
throw Exception("Flea cannot fly")
|
||||
fun crawl() = "Flea: crawl"
|
||||
}
|
||||
|
||||
fun Insect.basic() =
|
||||
this.walk() + " " +
|
||||
when(this) {
|
||||
is Flea -> this.crawl()
|
||||
else -> this.fly()
|
||||
}
|
||||
|
||||
interface SwimmingInsect {
|
||||
fun swim() = "${this.name}: swim"
|
||||
}
|
||||
|
||||
interface WaterWalker {
|
||||
fun walkWater() =
|
||||
"${this.name}: walk on water"
|
||||
}
|
||||
|
||||
class WaterBeetle : Insect(), SwimmingInsect
|
||||
class WaterStrider : Insect(), WaterWalker
|
||||
class WhirligigBeetle : Insect(),
|
||||
SwimmingInsect, WaterWalker
|
||||
|
||||
fun Insect.water() =
|
||||
when(this) {
|
||||
is SwimmingInsect -> this.swim()
|
||||
is WaterWalker -> this.walkWater()
|
||||
else -> "${this.name}: drown"
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val insects = listOf(
|
||||
HouseFly(), Flea(), WaterStrider(),
|
||||
WaterBeetle(), WhirligigBeetle()
|
||||
)
|
||||
insects.map { it.basic() } eq
|
||||
"[HouseFly: walk HouseFly: fly, " +
|
||||
"Flea: walk Flea: crawl, " +
|
||||
"WaterStrider: walk WaterStrider: fly, " +
|
||||
"WaterBeetle: walk WaterBeetle: fly, " +
|
||||
"WhirligigBeetle: walk " +
|
||||
"WhirligigBeetle: fly]"
|
||||
insects.map { it.water() } eq
|
||||
"[HouseFly: drown, Flea: drown, " +
|
||||
"WaterStrider: walk on water, " +
|
||||
"WaterBeetle: swim, " +
|
||||
"WhirligigBeetle: swim]"
|
||||
}
|
||||
```
|
||||
still make sense?
|
|
@ -1,10 +1,10 @@
|
|||
package typeCheckingExercise3
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestTypeCheckingExercise3 {
|
||||
@Test fun testSolution() {
|
||||
Assert.assertTrue("Tests not implemented for the task", false)
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// CreatingGenerics/CreatingGenericsSoln1.kt
|
||||
package creatingGenericsExercise1
|
||||
import atomictest.eq
|
||||
|
||||
fun interface Items<T> {
|
||||
fun next(): T?
|
||||
}
|
||||
|
||||
fun <T> itemIter(vararg items: T): Items<T> {
|
||||
var index = 0
|
||||
return Items {
|
||||
if (index >= items.size) null
|
||||
else items[index++]
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val s = itemIter("A", "B", "C")
|
||||
(0..3).map { s.next() } eq "[A, B, C, null]"
|
||||
val i = itemIter(1, 2, 3, 4, 5, 6, 7)
|
||||
(0..10).mapNotNull { i.next() } eq
|
||||
"[1, 2, 3, 4, 5, 6, 7]"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
|
@ -0,0 +1,14 @@
|
|||
## Creating Generics (#1)
|
||||
|
||||
Create a generic interface called `Items` with a single function `next()` that
|
||||
returns an object of the generic type, or `null`. Make `Items` usable for
|
||||
[SAM conversions](#sam-conversions).
|
||||
|
||||
Create a generic function called `itemIter()` that takes a `vararg items` of
|
||||
the type parameter and returns an `Items` object produced with a SAM
|
||||
conversion. The `Items` object closes over a `var index` to indicate the
|
||||
current element in `items`. Each call to `next()` produces the current element
|
||||
and increments `index`. When there are no more `items`, `next()` returns
|
||||
`null`.
|
||||
|
||||
The code in `main()` tests your solution.
|
|
@ -0,0 +1,10 @@
|
|||
package creatingGenericsExercise1
|
||||
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestCreatingGenericsExercise1 {
|
||||
@Test fun testSolution() {
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// CreatingGenerics/CreatingGenericsSoln2.kt
|
||||
package creatingGenericsExercise2
|
||||
import creatinggenerics.Crate
|
||||
import atomictest.eq
|
||||
|
||||
class CrateList<T> : ArrayList<Crate<T>>() {
|
||||
private class
|
||||
DecoratedCrate<T>(contents: T) :
|
||||
Crate<T>(contents) {
|
||||
override fun toString() = "[${get()}]"
|
||||
}
|
||||
fun add(item: T) {
|
||||
add(DecoratedCrate(item))
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val intCrates = CrateList<Int>()
|
||||
(0..7).forEach { intCrates.add(it) }
|
||||
intCrates eq
|
||||
"[[0], [1], [2], [3], [4], [5], [6], [7]]"
|
||||
val stringCrates = CrateList<String>()
|
||||
('a'..'h').map { it.toString() }
|
||||
.forEach { stringCrates.add(it) }
|
||||
stringCrates eq
|
||||
"[[a], [b], [c], [d], [e], [f], [g], [h]]"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
|
@ -0,0 +1,12 @@
|
|||
## Creating Generics (#2)
|
||||
|
||||
Create a generic class `CrateList` that inherits from an `ArrayList` of
|
||||
`Crate`. `Crate` has no `toString()`. To solve this problem, create a nested
|
||||
`private` class called `DecoratedCrate` that takes a generic argument of
|
||||
`contents` and inherits from `Crate`. Add a `toString()` to `DecoratedCrate`
|
||||
that produces a `String` consisting of the result of calling `get()` inside
|
||||
square brackets.
|
||||
|
||||
Define a member function `add()` that takes a generic `item` argument, creates
|
||||
a `DecoratedCrate` with it and adds the result to the `ArrayList`. The code in
|
||||
`main()` tests your solution.
|
|
@ -0,0 +1,10 @@
|
|||
package creatingGenericsExercise2
|
||||
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestCreatingGenericsExercise2 {
|
||||
@Test fun testSolution() {
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// CreatingGenerics/CreatingGenericsSoln3.kt
|
||||
package creatingGenericsExercise3
|
||||
import creatinggenerics.Can
|
||||
import creatinggenerics.Grape
|
||||
|
||||
interface InCrate<in T> {
|
||||
fun put(item: T)
|
||||
}
|
||||
|
||||
interface OutCrate<out T> {
|
||||
fun get(): T
|
||||
}
|
||||
|
||||
class Crate<T>(private var contents: T) :
|
||||
InCrate<T>, OutCrate<T> {
|
||||
override fun put(item: T) {
|
||||
contents = item
|
||||
}
|
||||
override fun get(): T = contents
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val cg: Crate<Grape> = Crate(Grape())
|
||||
val oc: OutCrate<Can> = cg
|
||||
val cc: Crate<Can> = Crate(Can())
|
||||
val ic: InCrate<Grape> = cc
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
|
@ -0,0 +1,6 @@
|
|||
## Creating Generics (#3)
|
||||
|
||||
Convert `InCrate` and `OutCrate` to interfaces. Create a new version of `Crate`
|
||||
that implements both `InCrate` and `OutCrate`. The code in `main()` tests your
|
||||
solution by upcasting from `Crate<Grape>` to `OutCrate<Can>` and from
|
||||
`Crate<Can>` to `InCrate<Grape>`.
|
|
@ -0,0 +1,10 @@
|
|||
package creatingGenericsExercise3
|
||||
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestCreatingGenericsExercise3 {
|
||||
@Test fun testSolution() {
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -1,2 +1,5 @@
|
|||
content:
|
||||
- Examples
|
||||
- Exercise 1
|
||||
- Exercise 2
|
||||
- Exercise 3
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// ExtensionLambdas/ExtensionLambdasSoln1.kt
|
||||
package extensionLambdasExercise1
|
||||
import atomictest.eq
|
||||
import kotlinx.collections.immutable.*
|
||||
|
||||
fun createString(
|
||||
build: StringBuilder.() -> Unit
|
||||
): String {
|
||||
val sb = StringBuilder()
|
||||
sb.build()
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun <T> createList(
|
||||
build: ArrayList<T>.() -> Unit
|
||||
): List<T> {
|
||||
val list = ArrayList<T>()
|
||||
list.build()
|
||||
return list.toImmutableList()
|
||||
}
|
||||
|
||||
fun <K, V> createMap(
|
||||
build: HashMap<K, V>.() -> Unit
|
||||
): Map<K, V> {
|
||||
val map = HashMap<K, V>()
|
||||
map.build()
|
||||
return map.toImmutableMap()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun main() {
|
||||
createString {
|
||||
(1..10).forEach { append(it) }
|
||||
} eq buildString {
|
||||
(1..10).forEach { append(it) }
|
||||
}
|
||||
createList<String> {
|
||||
(1..10).forEach { add(it.toString()) }
|
||||
} eq buildList {
|
||||
(1..10).forEach { add(it.toString()) }
|
||||
}
|
||||
createMap<Char, Int> {
|
||||
('a'..'j').forEachIndexed { n, c ->
|
||||
put(c, n)
|
||||
}
|
||||
} eq buildMap {
|
||||
('a'..'j').forEachIndexed { n, c ->
|
||||
put(c, n)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
|
@ -0,0 +1,20 @@
|
|||
## Extension Lambdas (#1)
|
||||
|
||||
Define the following functions so they behave the same as their standard
|
||||
library counterparts:
|
||||
|
||||
- `createString()` behaves like `buildString()`. Start by creating a new
|
||||
instance of `StringBuilder`, call the extension lambda argument on it, then
|
||||
return the `String` result.
|
||||
|
||||
- `createList()` behaves like `buildList()`. This function has one generic
|
||||
parameter. Create an `ArrayList<T>`, call the extension lambda argument on it,
|
||||
and return the `List` in immutable form.
|
||||
|
||||
- `createMap()` behaves like `buildMap()`. This function has two generic
|
||||
parameters. Create a `HashMap<K, V>`, call the extension lambda argument on it,
|
||||
and return the `Map` in immutable form.
|
||||
|
||||
The code in `main()` tests your functions against the standard library
|
||||
versions. Notice that `buildList()` and `buildMap()` infer their generic
|
||||
parameters.
|
|
@ -0,0 +1,10 @@
|
|||
package extensionLambdasExercise1
|
||||
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestExtensionLambdasExercise1 {
|
||||
@Test fun testSolution() {
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// ExtensionLambdas/ExtensionLambdasSoln2.kt
|
||||
package extensionLambdasExercise2
|
||||
import sandwich.*
|
||||
import atomictest.eq
|
||||
|
||||
fun sandwich2(
|
||||
prepare: Sandwich.() -> Unit = { this },
|
||||
fillings: Sandwich.() -> Unit
|
||||
): Sandwich {
|
||||
val sandwich = Sandwich()
|
||||
sandwich.prepare()
|
||||
sandwich.fillings()
|
||||
return sandwich
|
||||
}
|
||||
|
||||
fun Sandwich.sandwich3(
|
||||
fillings: Sandwich.() -> Unit
|
||||
): Sandwich {
|
||||
fillings()
|
||||
return this
|
||||
}
|
||||
|
||||
val PBJ1 = sandwich2 {
|
||||
add(PeanutButter())
|
||||
add(GrapeJelly())
|
||||
}
|
||||
|
||||
val PBJ2 = sandwich2({ toast() }) {
|
||||
add(PeanutButter())
|
||||
add(GrapeJelly())
|
||||
}
|
||||
|
||||
val PBJ3 = Sandwich().toast().sandwich3 {
|
||||
add(PeanutButter())
|
||||
add(GrapeJelly())
|
||||
}
|
||||
|
||||
val PBJ4 = Sandwich().toast().sandwich3 {
|
||||
add(PeanutButter())
|
||||
add(GrapeJelly())
|
||||
}.grill()
|
||||
|
||||
fun main() {
|
||||
PBJ1 eq "[PeanutButter, GrapeJelly]"
|
||||
PBJ2 eq "[Toast, PeanutButter, GrapeJelly]"
|
||||
PBJ3 eq "[Toast, PeanutButter, GrapeJelly]"
|
||||
PBJ4 eq
|
||||
"[Toast, PeanutButter, GrapeJelly, Grill]"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
|
@ -0,0 +1,11 @@
|
|||
## Extension Lambdas (#2)
|
||||
|
||||
Import `sandwich.*` and create a function `sandwich2()` following the example
|
||||
of `sandwich()`. Insert a first parameter `prepare`, which is an extension
|
||||
lambda that allows the user to choose whether to toast the `Sandwich`, with the
|
||||
default untoasted.
|
||||
|
||||
Add a function `sandwich3()` which is an extension function for `Sandwich`. The
|
||||
user can provide a `Sandwich` receiver that may or may not be already toasted.
|
||||
|
||||
The starter code and the code in `main()` tests your functions.
|
|
@ -0,0 +1,10 @@
|
|||
package extensionLambdasExercise2
|
||||
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestExtensionLambdasExercise2 {
|
||||
@Test fun testSolution() {
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// ExtensionLambdas/ExtensionLambdasSoln3.kt
|
||||
package extensionLambdasExercise3
|
||||
import atomictest.eq
|
||||
|
||||
open class Cleanser : ArrayList<String>() {
|
||||
fun selectContainer() {
|
||||
add("Container selected")
|
||||
}
|
||||
fun sealContainer() {
|
||||
add("Container sealed")
|
||||
}
|
||||
fun detergent() { add("detergent") }
|
||||
fun abrasive() { add("abrasive") }
|
||||
fun ammonia() { add("ammonia") }
|
||||
fun water() { add("water") }
|
||||
}
|
||||
|
||||
class SprayCleanser : Cleanser() {
|
||||
fun selectSprayer() {
|
||||
add("Sprayer selected")
|
||||
}
|
||||
}
|
||||
|
||||
fun cleanser(
|
||||
formula: Cleanser.() -> Unit
|
||||
): Cleanser {
|
||||
val result = Cleanser()
|
||||
result.selectContainer()
|
||||
result.formula()
|
||||
result.sealContainer()
|
||||
return result
|
||||
}
|
||||
|
||||
fun sprayCleanser(
|
||||
formula: SprayCleanser.() -> Unit
|
||||
): SprayCleanser {
|
||||
val result = SprayCleanser()
|
||||
result.selectContainer()
|
||||
result.selectSprayer()
|
||||
result.formula()
|
||||
result.sealContainer()
|
||||
return result
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val c: Cleanser = cleanser {
|
||||
detergent()
|
||||
abrasive()
|
||||
}
|
||||
c eq "[Container selected, detergent, " +
|
||||
"abrasive, Container sealed]"
|
||||
val sc: SprayCleanser = sprayCleanser {
|
||||
detergent()
|
||||
ammonia()
|
||||
water()
|
||||
}
|
||||
sc eq "[Container selected, " +
|
||||
"Sprayer selected, detergent, " +
|
||||
"ammonia, water, Container sealed]"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
|
@ -0,0 +1,5 @@
|
|||
## Extension Lambdas (#3)
|
||||
|
||||
The starter code contains definitions for `class Cleanser` and `class
|
||||
SprayCleanser`. Write the functions `cleanser()` and `sprayCleanser()` so the
|
||||
code in `main()` works correctly.
|
|
@ -0,0 +1,10 @@
|
|||
package extensionLambdasExercise3
|
||||
|
||||
import org.junit.Test
|
||||
import util.unimplementedTest
|
||||
|
||||
class TestExtensionLambdasExercise3 {
|
||||
@Test fun testSolution() {
|
||||
unimplementedTest()
|
||||
}
|
||||
}
|
|
@ -1,2 +1,5 @@
|
|||
content:
|
||||
- Examples
|
||||
- Exercise 1
|
||||
- Exercise 2
|
||||
- Exercise 3
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// Hashing/EasyKeys.kt
|
||||
package hashing
|
||||
import atomictest.eq
|
||||
|
||||
data class Employee(
|
||||
val first: String,
|
||||
val last: String, val id: Int
|
||||
)
|
||||
|
||||
fun main() {
|
||||
val employees = HashSet(setOf(
|
||||
Employee("Lucia", "Dubois", 1),
|
||||
Employee("Bob", "Dobbs", 2),
|
||||
Employee("Ilsa", "Schmidt", 3)))
|
||||
employees.joinToString(separator = "\n") eq
|
||||
"""
|
||||
Employee(first=Bob, last=Dobbs, id=2)
|
||||
Employee(first=Lucia, last=Dubois, id=1)
|
||||
Employee(first=Ilsa, last=Schmidt, id=3)
|
||||
""".trimIndent()
|
||||
|
||||
(Employee("Ilsa", "Schmidt", 3)
|
||||
in employees) eq true
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// Hashing/HashCodeFailure.kt
|
||||
import atomictest.*
|
||||
|
||||
class NotDataClass(id: String)
|
||||
data class DataClass(val id: String)
|
||||
|
||||
fun main() {
|
||||
val key = NotDataClass("A")
|
||||
val key2 = NotDataClass("A")
|
||||
key.hashCode() neq key2.hashCode() // [1]
|
||||
key.equals(key2) eq false // [2]
|
||||
val hm = hashMapOf(key to "Hello")
|
||||
hm[key] eq "Hello"
|
||||
hm[key2] eq null // [3]
|
||||
|
||||
val dckey = DataClass("A")
|
||||
val dckey2 = DataClass("A")
|
||||
dckey.hashCode() eq dckey2.hashCode() // [4]
|
||||
dckey.equals(dckey2) eq true // [5]
|
||||
val hmdc = hashMapOf(dckey to "Hello")
|
||||
hmdc[dckey] eq "Hello"
|
||||
hmdc[dckey2] eq "Hello" // [6]
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// Hashing/KeyFailure.kt
|
||||
package hashing
|
||||
import atomictest.eq
|
||||
|
||||
data class Key(var id: String)
|
||||
|
||||
fun main() {
|
||||
val key = Key("A")
|
||||
val hm = hashMapOf(key to "Hello")
|
||||
hm eq "{Key(id=A)=Hello}"
|
||||
hm[key] eq "Hello" // [1]
|
||||
|
||||
key.id = "Goodbye"
|
||||
hm eq "{Key(id=Goodbye)=Hello}"
|
||||
hm[key] eq null // [2]
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
// Hashing/Pets.kt
|
||||
package hashing
|
||||
import atomictest.eq
|
||||
|
||||
interface Pet {
|
||||
companion object {
|
||||
var n = 0
|
||||
fun next() = n++
|
||||
}
|
||||
}
|
||||
|
||||
data class Cat(
|
||||
val name: String,
|
||||
val id: Int = Pet.next()
|
||||
) : Pet
|
||||
|
||||
data class Dog(
|
||||
val name: String,
|
||||
val id: Int = Pet.next()
|
||||
) : Pet
|
||||
|
||||
data class Rat(
|
||||
val name: String,
|
||||
val id: Int = Pet.next()
|
||||
) : Pet
|
||||
|
||||
fun main() {
|
||||
val pets = HashSet(setOf(
|
||||
Cat("Elsie"),
|
||||
Dog("Rufus"),
|
||||
Rat("Fizzy"),
|
||||
Cat("Stanford"),
|
||||
Rat("Freckly"),
|
||||
Rat("Fuzzy")))
|
||||
pets.joinToString(separator = "\n") eq
|
||||
"""
|
||||
Cat(name=Stanford, id=3)
|
||||
Rat(name=Freckly, id=4)
|
||||
Rat(name=Fuzzy, id=5)
|
||||
Rat(name=Fizzy, id=2)
|
||||
Cat(name=Elsie, id=0)
|
||||
Dog(name=Rufus, id=1)
|
||||
""".trimIndent()
|
||||
|
||||
(pets.first() in pets) eq true
|
||||
(Dog("Pugsly") in pets) eq false
|
||||
// Because each object has a unique id:
|
||||
(Dog("Rufus") in pets) eq false
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Hashing/SimpleHashing.kt
|
||||
import atomictest.eq
|
||||
|
||||
fun main() {
|
||||
val keys = 'A'..'z'
|
||||
val hm = HashMap(
|
||||
keys.associate { it to keys.indexOf(it) })
|
||||
hm['Z'] eq 25
|
||||
hm['x'] = 42
|
||||
hm['x'] eq 42
|
||||
|
||||
val items = 'A'..'F'
|
||||
val hs = HashSet(
|
||||
items + items + items + items + items
|
||||
)
|
||||
hs eq "[A, B, C, D, E, F]"
|
||||
('C' in hs) eq true
|
||||
('c' in hs) eq false
|
||||
hs.containsAll(('B'..'D').toSet()) eq true
|
||||
hs.intersect(('D'..'Z').toSet()) eq
|
||||
"[D, E, F]"
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
// Hashing/StringHashCode.kt
|
||||
import atomictest.eq
|
||||
|
||||
fun main() {
|
||||
"Hello".hashCode() eq "Hello".hashCode();
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// Hashing/UnpredictableHashing.kt
|
||||
import atomictest.eq
|
||||
|
||||
fun main() {
|
||||
"Hash order is unpredictable".toHashSet() eq
|
||||
"[H, , a, b, c, d, e, h, i, " +
|
||||
"l, n, o, p, r, s, t, u]"
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
type: theory
|
||||
files:
|
||||
- name: src/SimpleHashing.kt
|
||||
visible: true
|
||||
- name: src/UnpredictableHashing.kt
|
||||
visible: true
|
||||
- name: src/Pets.kt
|
||||
visible: true
|
||||
- name: src/KeyFailure.kt
|
||||
visible: true
|
||||
- name: src/HashCodeFailure.kt
|
||||
visible: true
|
||||
- name: src/StringHashCode.kt
|
||||
visible: true
|
||||
- name: src/EasyKeys.kt
|
||||
visible: true
|
|
@ -1,2 +0,0 @@
|
|||
id: 1305811
|
||||
update_date: Tue, 12 May 2020 16:26:34 UTC
|
|
@ -1,4 +0,0 @@
|
|||
## Hashing
|
||||
|
||||
Examples accompanying the atom.
|
||||
[Read "Hashing" atom online.](https://stepik.org/lesson/350555/step/1)
|
|
@ -1,22 +0,0 @@
|
|||
package hashingExercise1
|
||||
|
||||
data class Contact(
|
||||
val name: String,
|
||||
val number: String
|
||||
)
|
||||
|
||||
class Person(val name: String)
|
||||
|
||||
fun main() {
|
||||
val set1 = setOf(
|
||||
Person("Alice"),
|
||||
Person("Alice"))
|
||||
val set2 = setOf(
|
||||
Contact("Alice", "123-456"),
|
||||
Contact("Alice", "123-456"))
|
||||
set1.size // 1 or 2? Write you guess below.
|
||||
set2.size // 1 or 2? Write you guess below.
|
||||
}
|
||||
|
||||
fun getSet1Size(): Int = 2
|
||||
fun getSet2Size(): Int = 1
|
|
@ -1,15 +0,0 @@
|
|||
type: edu
|
||||
files:
|
||||
- name: src/Task.kt
|
||||
visible: true
|
||||
placeholders:
|
||||
- offset: 405
|
||||
length: 1
|
||||
placeholder_text: TODO()
|
||||
- offset: 432
|
||||
length: 1
|
||||
placeholder_text: TODO()
|
||||
- name: test/Tests.kt
|
||||
visible: false
|
||||
feedback_link: |
|
||||
https://docs.google.com/forms/d/e/1FAIpQLSdkaliSwYkjiV21bZl0yP-In2g5p17sAQCfaGjyHx_QYMWTiQ/viewform?usp=pp_url&entry.189755027=Usability+%2F+Data+Classes+%2F+Exercise1
|
|
@ -1,2 +0,0 @@
|
|||
id: 1305812
|
||||
update_date: Tue, 12 May 2020 16:26:35 UTC
|
|
@ -1,26 +0,0 @@
|
|||
## Hashing (#1)
|
||||
|
||||
Test your understanding of how `Set`s store instances of data classes. Guess the
|
||||
size of `Set`s `set1` and `set2` in the following code:
|
||||
|
||||
```kotlin
|
||||
data class Contact(
|
||||
val name: String,
|
||||
val number: String
|
||||
)
|
||||
|
||||
class Person(val name: String)
|
||||
|
||||
fun main() {
|
||||
val set1 = setOf(
|
||||
Person("Alice"),
|
||||
Person("Alice"))
|
||||
val set2 = setOf(
|
||||
Contact("Alice", "123-456"),
|
||||
Contact("Alice", "123-456"))
|
||||
set1.size // 1 or 2?
|
||||
set2.size // 1 or 2?
|
||||
}
|
||||
```
|
||||
|
||||
You can easily check your guess by printing the contents of the `Set`s.
|
|
@ -1,20 +0,0 @@
|
|||
package hashingExercise1
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runners.MethodSorters
|
||||
import util.TIMEOUT
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class TestHashingExercise1 {
|
||||
@Test(timeout = TIMEOUT)
|
||||
fun testSizeOfFirstSet() {
|
||||
Assert.assertTrue("Wrong answer for set1", getSet1Size() == 2)
|
||||
}
|
||||
|
||||
@Test(timeout = TIMEOUT)
|
||||
fun testSizeOfSecondSet() {
|
||||
Assert.assertTrue("Wrong answer for set2", getSet2Size() == 1)
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
content:
|
||||
- Examples
|
||||
- Exercise 1
|
|
@ -1,3 +0,0 @@
|
|||
id: 354564
|
||||
update_date: Tue, 12 May 2020 16:26:31 UTC
|
||||
unit: 338605
|
|
@ -1,35 +0,0 @@
|
|||
// Immutability/ColorBlend.kt
|
||||
package colorblend
|
||||
import atomictest.eq
|
||||
import paintcolors.Color
|
||||
import paintcolors.Color.*
|
||||
|
||||
fun blend(a: Color, b: Color) = when {
|
||||
a == b -> a
|
||||
a == brown || b == brown -> brown
|
||||
else -> when (a to b) {
|
||||
red to blue, blue to red -> purple
|
||||
red to yellow, yellow to red -> orange
|
||||
blue to yellow, yellow to blue -> green
|
||||
else -> {
|
||||
// Interesting but not accurate:
|
||||
val values = values()
|
||||
values[
|
||||
(a.ordinal + b.ordinal) % values.size]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test(
|
||||
mix: (a: Color, b: Color) -> Color?
|
||||
) {
|
||||
mix(red, red) eq red
|
||||
mix(purple, brown) eq brown
|
||||
mix(red, yellow) eq orange
|
||||
mix(yellow, blue) eq green
|
||||
mix(purple, orange) eq blue // Not accurate
|
||||
}
|
||||
|
||||
fun main() {
|
||||
test(::blend)
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// Immutability/DataClassCopy.kt
|
||||
import atomictest.eq
|
||||
|
||||
data class DC(
|
||||
val a: String,
|
||||
val b: String,
|
||||
val c: String,
|
||||
val d: String
|
||||
)
|
||||
|
||||
fun main() {
|
||||
val dc = DC("one", "two", "three", "four")
|
||||
val dc2 = dc.copy(b = "bouncy", d = "red")
|
||||
dc eq "DC(a=one, b=two, c=three, d=four)"
|
||||
dc2 eq "DC(a=one, b=bouncy, c=three, d=red)"
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Immutability/MutableBlendMap.kt
|
||||
package mutableblendmap
|
||||
import paintcolors.Color
|
||||
|
||||
class BlendMap {
|
||||
private val map =
|
||||
mutableMapOf<Pair<Color, Color>, Color>()
|
||||
|
||||
init {
|
||||
for (a in Color.values()) {
|
||||
for (b in Color.values()) {
|
||||
map[a to b] = colorblend.blend(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun blend(a: Color, b: Color) = map[a to b]
|
||||
}
|
||||
|
||||
fun main() {
|
||||
colorblend.test(BlendMap()::blend)
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Immutability/MutableBlendMap2.kt
|
||||
package mutableblendmap2
|
||||
import paintcolors.Color
|
||||
|
||||
class BlendMap {
|
||||
private val
|
||||
imap: Map<Pair<Color, Color>, Color>
|
||||
|
||||
init {
|
||||
val map = mutableMapOf<
|
||||
Pair<Color, Color>, Color>()
|
||||
for (a in Color.values()) {
|
||||
for (b in Color.values()) {
|
||||
map[a to b] = colorblend.blend(a, b)
|
||||
}
|
||||
}
|
||||
imap = map.toMap() // Read-only Map
|
||||
}
|
||||
|
||||
fun blend(a: Color, b: Color) = imap[a to b]
|
||||
}
|
||||
|
||||
fun main() {
|
||||
colorblend.test(BlendMap()::blend)
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// Immutability/PaintColors.kt
|
||||
package paintcolors
|
||||
|
||||
enum class Color {
|
||||
red, blue, yellow, purple,
|
||||
green, orange, brown
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// Immutability/ReadOnlyBlendMap.kt
|
||||
package readonlyblendmap
|
||||
import paintcolors.Color
|
||||
|
||||
val combinations = Color.values()
|
||||
.flatMap { a ->
|
||||
Color.values().map { b -> a to b }
|
||||
}
|
||||
|
||||
val blendMap = combinations.map {
|
||||
it to colorblend.blend(it.first, it.second)
|
||||
}.toMap()
|
||||
|
||||
fun blend(a: Color, b: Color) =
|
||||
blendMap[a to b]
|
||||
|
||||
fun main() {
|
||||
colorblend.test(::blend)
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// Immutability/ReadOnlyBlendMap2.kt
|
||||
package readonlyblendmap2
|
||||
import paintcolors.Color
|
||||
|
||||
val blendMap = Color.values()
|
||||
.flatMap { a ->
|
||||
Color.values().map { b -> a to b }
|
||||
}
|
||||
.map {
|
||||
it to colorblend.blend(it.first, it.second)
|
||||
}
|
||||
.toMap()
|
||||
|
||||
fun blend(a: Color, b: Color) =
|
||||
blendMap[a to b]
|
||||
|
||||
fun main() {
|
||||
colorblend.test(::blend)
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// Immutability/ReadOnlyBlendMap3.kt
|
||||
package readonlyblendmap3
|
||||
import paintcolors.Color
|
||||
|
||||
class BlendMap {
|
||||
private val map = Color.values()
|
||||
.flatMap { a ->
|
||||
Color.values().map { b -> a to b }
|
||||
}
|
||||
.map {
|
||||
it to colorblend.blend(
|
||||
it.first, it.second)
|
||||
}
|
||||
.toMap()
|
||||
|
||||
fun blend(a: Color, b: Color) = map[a to b]
|
||||
}
|
||||
|
||||
fun main() {
|
||||
colorblend.test(BlendMap()::blend)
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Immutability/ReadOnlyBlendMap4.kt
|
||||
package readonlyblendmap4
|
||||
import paintcolors.Color
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
val map1: Map<Pair<Color, Color>, Color> =
|
||||
buildMap {
|
||||
for (a in Color.values()) {
|
||||
for (b in Color.values()) {
|
||||
this[a to b] = colorblend.blend(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
//colorblend.test(BlendMap()::blend)
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Immutability/XYZFlatMap.kt
|
||||
package xyzflatmap
|
||||
|
||||
enum class XYZ { x, y, z }
|
||||
|
||||
fun main() {
|
||||
val flat = XYZ.values().flatMap { a ->
|
||||
XYZ.values().map { b ->
|
||||
a to b
|
||||
}
|
||||
}
|
||||
flat.forEach { println(it) }
|
||||
}
|
||||
/* Output:
|
||||
(x, x)
|
||||
(x, y)
|
||||
(x, z)
|
||||
(y, x)
|
||||
(y, y)
|
||||
(y, z)
|
||||
(z, x)
|
||||
(z, y)
|
||||
(z, z)
|
||||
*/
|
|
@ -1,23 +0,0 @@
|
|||
// Immutability/XYZMap.kt
|
||||
package xyzmap
|
||||
|
||||
enum class XYZ { x, y, z }
|
||||
|
||||
fun main() {
|
||||
val normal = XYZ.values().map { a ->
|
||||
println()
|
||||
XYZ.values().map { b ->
|
||||
print("$a:$b,"); a to b
|
||||
}
|
||||
}
|
||||
println()
|
||||
normal.forEach { println(it) }
|
||||
}
|
||||
/* Output:
|
||||
x:x,x:y,x:z,
|
||||
y:x,y:y,y:z,
|
||||
z:x,z:y,z:z,
|
||||
[(x, x), (x, y), (x, z)]
|
||||
[(y, x), (y, y), (y, z)]
|
||||
[(z, x), (z, y), (z, z)]
|
||||
*/
|
|
@ -1,24 +0,0 @@
|
|||
type: theory
|
||||
files:
|
||||
- name: src/PaintColors.kt
|
||||
visible: true
|
||||
- name: src/ColorBlend.kt
|
||||
visible: true
|
||||
- name: src/MutableBlendMap.kt
|
||||
visible: true
|
||||
- name: src/MutableBlendMap2.kt
|
||||
visible: true
|
||||
- name: src/XYZMap.kt
|
||||
visible: true
|
||||
- name: src/XYZFlatMap.kt
|
||||
visible: true
|
||||
- name: src/ReadOnlyBlendMap.kt
|
||||
visible: true
|
||||
- name: src/ReadOnlyBlendMap2.kt
|
||||
visible: true
|
||||
- name: src/ReadOnlyBlendMap3.kt
|
||||
visible: true
|
||||
- name: src/ReadOnlyBlendMap4.kt
|
||||
visible: true
|
||||
- name: src/DataClassCopy.kt
|
||||
visible: true
|
|
@ -1,2 +0,0 @@
|
|||
id: 1305810
|
||||
update_date: Tue, 12 May 2020 16:26:30 UTC
|
|
@ -1,4 +0,0 @@
|
|||
## Immutability
|
||||
|
||||
Examples accompanying the atom.
|
||||
[Read "Immutability" atom online.](https://stepik.org/lesson/350554/step/1)
|
|
@ -1,2 +0,0 @@
|
|||
content:
|
||||
- Examples
|
|
@ -1,3 +0,0 @@
|
|||
id: 354563
|
||||
update_date: Tue, 12 May 2020 16:26:27 UTC
|
||||
unit: 338604
|
|
@ -1,11 +0,0 @@
|
|||
// LambdaWithReceiver/AnonymousFunction.kt
|
||||
package lambdawithreceiver
|
||||
import atomictest.eq
|
||||
|
||||
fun main() {
|
||||
val divides = fun Int.(d: Int): Boolean {
|
||||
return this % d == 0
|
||||
}
|
||||
10.divides(2) eq true
|
||||
10.divides(3) eq false
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// LambdaWithReceiver/BuildLists.kt
|
||||
package buildinglists
|
||||
import atomictest.eq
|
||||
|
||||
fun main() {
|
||||
val strings: List<String> = buildList {
|
||||
add("Chars:") // [1]
|
||||
for (ch in 'a'..'d') {
|
||||
add("$ch")
|
||||
}
|
||||
}
|
||||
strings eq
|
||||
listOf("Chars:", "a", |