Skip to content

Commit

Permalink
Kotlin / Bob / DigDeeper: Add a pattern matching approach using when-…
Browse files Browse the repository at this point in the history
…expression (#629)

* Add approach to introduction

* Add snippet.txt and content.md

* Add entry in config.json

* Fix typo in config.json

* Reduce snippet length to 8 lines

* Use proposed one-liner in function isYelling
  • Loading branch information
micha-b authored Apr 9, 2024
1 parent 09e762d commit 8e81747
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
9 changes: 9 additions & 0 deletions exercises/practice/bob/.approaches/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
"authors": [
"bobahop"
]
},
{
"uuid": "7aebc1df-c23a-42c9-90c4-f022e40d67e9",
"slug": "when-expression",
"title":"when expression",
"blurb": "Use a when expression to return the answer.",
"authors": [
"micha-b"
]
}
]
}
18 changes: 18 additions & 0 deletions exercises/practice/bob/.approaches/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ object Bob {

For more information, check the [Answer `List` approach][approach-answer-list].

## Approach: `when` expression

```kotlin
object Bob {
fun hey(statement: String): String =
when {
statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!"
statement.isQuestion() -> "Sure."
statement.isYelling() -> "Whoa, chill out!"
statement.isSilence() -> "Fine. Be that way!"
else -> "Whatever."
}
}
```

For more information, check the [`when` expression approach][approach-when]

## Which approach to use?

The choice between `if` expressions and answers `List` can be made by perceived readability.
Expand All @@ -65,3 +82,4 @@ The choice between `if` expressions and answers `List` can be made by perceived
[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
[approach-if]: https://exercism.org/tracks/kotlin/exercises/bob/approaches/if-expressions
[approach-answer-list]: https://exercism.org/tracks/kotlin/exercises/bob/approaches/answer-list
[approach-when]: https://exercism.org/tracks/kotlin/exercises/bob/approaches/when-expression
54 changes: 54 additions & 0 deletions exercises/practice/bob/.approaches/when-expression/content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# `when` expressions

```kotlin
object Bob {
fun hey(statement: String): String =
when {
statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!"
statement.isQuestion() -> "Sure."
statement.isYelling() -> "Whoa, chill out!"
statement.isSilence() -> "Fine. Be that way!"
else -> "Whatever."
}

private fun String.isSilence(): Boolean = this.isBlank()
private fun String.isQuestion(): Boolean = this.trim().endsWith('?')
private fun String.isYelling(): Boolean = any(Char::isLetter) && toUpperCase() == this
}
```

In this approach you have a `when` expression containing different so-called branches that can be matched using the corresponding patterns.
As soon as one of these patterns on the left side of the arrow (`->`) is matched ...

1. the value on the right side
2. the block on the right side is executed and the value retuned from the block

... is returned from the `when` expression.

Only one branch is matched in one execution of the `when` expression. The branches are matched from top to bottom and the first branch in which the condition evaluates to `true` is selected.
If none of the given conditions matches the `else` branch is selected and returned.

~~~~exercism/caution
Depending on what patterns are on the left side of your branches the order of branches is important to the correct execution of the `when` expression since the first matching branch is selected.
~~~~

An [object declaration][object] is used to define `Bob` as essentially a [singleton][singleton] object instantiation of the class.
This is sufficient, since there is no object state that needs to change with each call of the `hey` method.

Inside this object there are some `private` [extension methods as members][extension-members] of the `object`. This adds these methods to the `String` data type for `private` usage of these methods in this `object`. This allows calling the methods directly on the `String` instead of passing the `String` to the method.
(More about extension methods in general [here][extension-general])

These extension methods check for:

1. `isSilence()`: a blank string
2. `isQuestion()`: a string with the last non-whitespace-character being a question mark
3. `isYelling()`: a string with all letters in uppercase

When combining these methods as in the `when` expression above you can map all the cases required by the exercise.


[when]: https://kotlinlang.org/docs/control-flow.html#when-expression
[object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview
[singleton]: https://en.wikipedia.org/wiki/Singleton_pattern
[extension-members]: https://kotlinlang.org/docs/extensions.html#declaring-extensions-as-members
[extension-general]: https://kotlinlang.org/docs/extensions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fun hey(statement: String): String =
when {
statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!"
statement.isQuestion() -> "Sure."
statement.isYelling() -> "Whoa, chill out!"
statement.isSilence() -> "Fine. Be that way!"
else -> "Whatever."
}

0 comments on commit 8e81747

Please sign in to comment.