Skip to content

Add code tabs to fun-write-method-returns-function #2664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
nokogiri (1.13.10-arm64-darwin)
racc (~> 1.4)
nokogiri (1.13.10-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.13.10-x86_64-linux)
Expand Down Expand Up @@ -81,6 +83,7 @@ GEM
yell (2.2.2)

PLATFORMS
arm64-darwin-22
x86_64-darwin-21
x86_64-linux

Expand Down
76 changes: 76 additions & 0 deletions _overviews/scala3-book/fun-write-method-returns-function.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,72 @@ Once again we start with a problem statement:
Given that statement, you can start building `greet`.
You know it’s going to be a method:

{% tabs fun-write-method-returns-function-1 %}
{% tab 'Scala 2 and 3' %}
```scala
def greet()
```
{% endtab %}
{% endtabs %}

You also know this method will return a function that (a) takes a `String` parameter, and (b) prints that string using `println`.
Therefore that function has the type, `String => Unit`:

{% tabs fun-write-method-returns-function-2 %}
{% tab 'Scala 2 and 3' %}
```scala
def greet(): String => Unit = ???
----------------
```
{% endtab %}
{% endtabs %}

Now you just need a method body.
You know that the method needs to return a function, and that function takes a `String` and prints it.
This anonymous function matches that description:

{% tabs fun-write-method-returns-function-3 %}
{% tab 'Scala 2 and 3' %}
```scala
(name: String) => println(s"Hello, $name")
```
{% endtab %}
{% endtabs %}

Now you just return that function from the method:

{% tabs fun-write-method-returns-function-4 %}
{% tab 'Scala 2 and 3' %}
```scala
// a method that returns a function
def greet(): String => Unit =
(name: String) => println(s"Hello, $name")
```
{% endtab %}
{% endtabs %}

Because this method returns a function, you get the function by calling `greet()`.
This is a good step to do in the REPL because it verifies the type of the new function:

{% tabs fun-write-method-returns-function-5 %}
{% tab 'Scala 2 and 3' %}
````
scala> val greetFunction = greet()
val greetFunction: String => Unit = Lambda....
-----------------------------
````
{% endtab %}
{% endtabs %}

Now you can call `greetFunction`:

{% tabs fun-write-method-returns-function-6 %}
{% tab 'Scala 2 and 3' %}
```scala
greetFunction("Joe") // prints "Hello, Joe"
```
{% endtab %}
{% endtabs %}

Congratulations, you just created a method that returns a function, and then executed that function.

Expand All @@ -72,36 +96,52 @@ Congratulations, you just created a method that returns a function, and then exe
Our method would be more useful if you could pass in a greeting, so let’s do that.
All you have to do is pass the greeting in as a parameter to the `greet` method, and use it in the string inside `println`:

{% tabs fun-write-method-returns-function-7 %}
{% tab 'Scala 2 and 3' %}
```scala
def greet(theGreeting: String): String => Unit =
(name: String) => println(s"$theGreeting, $name")
```
{% endtab %}
{% endtabs %}

Now when you call your method, the process is more flexible because you can change the greeting.
This is what it looks like when you create a function from this method:

{% tabs fun-write-method-returns-function-8 %}
{% tab 'Scala 2 and 3' %}
````
scala> val sayHello = greet("Hello")
val sayHello: String => Unit = Lambda.....
------------------------
````
{% endtab %}
{% endtabs %}

The REPL type signature output shows that `sayHello` is a function that takes a `String` input parameter and returns `Unit` (nothing).
So now when you give `sayHello` a `String`, it prints the greeting:

{% tabs fun-write-method-returns-function-9 %}
{% tab 'Scala 2 and 3' %}
```scala
sayHello("Joe") // prints "Hello, Joe"
```
{% endtab %}
{% endtabs %}

You can also change the greeting to create new functions, as desired:

{% tabs fun-write-method-returns-function-10 %}
{% tab 'Scala 2 and 3' %}
```scala
val sayCiao = greet("Ciao")
val sayHola = greet("Hola")

sayCiao("Isabella") // prints "Ciao, Isabella"
sayHola("Carlos") // prints "Hola, Carlos"
```
{% endtab %}
{% endtabs %}



Expand All @@ -116,27 +156,53 @@ A first thing you know is that you want to create a method that (a) takes a “d
Furthermore, because that function prints a string that it’s given, you know it has the type `String => Unit`.
With that information you write the method signature:

{% tabs fun-write-method-returns-function-11 %}
{% tab 'Scala 2 and 3' %}
```scala
def createGreetingFunction(desiredLanguage: String): String => Unit = ???
```
{% endtab %}
{% endtabs %}

Next, because you know that the possible functions you’ll return take a string and print it, you can write two anonymous functions for the English and French languages:

{% tabs fun-write-method-returns-function-12 %}
{% tab 'Scala 2 and 3' %}
```scala
(name: String) => println(s"Hello, $name")
(name: String) => println(s"Bonjour, $name")
```
{% endtab %}
{% endtabs %}

Inside a method it might be a little more readable if you give those anonymous functions some names, so let’s assign them to two variables:

{% tabs fun-write-method-returns-function-13 %}
{% tab 'Scala 2 and 3' %}
```scala
val englishGreeting = (name: String) => println(s"Hello, $name")
val frenchGreeting = (name: String) => println(s"Bonjour, $name")
```
{% endtab %}
{% endtabs %}

Now all you need to do is (a) return `englishGreeting` if the `desiredLanguage` is English, and (b) return `frenchGreeting` if the `desiredLanguage` is French.
One way to do that is with a `match` expression:

{% tabs fun-write-method-returns-function-14 class=tabs-scala-version %}
{% tab 'Scala 2' %}
```scala
def createGreetingFunction(desiredLanguage: String): String => Unit = {
val englishGreeting = (name: String) => println(s"Hello, $name")
val frenchGreeting = (name: String) => println(s"Bonjour, $name")
desiredLanguage match {
case "english" => englishGreeting
case "french" => frenchGreeting
}
}
```
{% endtab %}
{% tab 'Scala 3' %}
```scala
def createGreetingFunction(desiredLanguage: String): String => Unit =
val englishGreeting = (name: String) => println(s"Hello, $name")
Expand All @@ -145,23 +211,33 @@ def createGreetingFunction(desiredLanguage: String): String => Unit =
case "english" => englishGreeting
case "french" => frenchGreeting
```
{% endtab %}
{% endtabs %}

And that’s the final method.
Notice that returning a function value from a method is no different than returning a string or integer value.

This is how `createGreetingFunction` builds a French-greeting function:

{% tabs fun-write-method-returns-function-15 %}
{% tab 'Scala 2 and 3' %}
```scala
val greetInFrench = createGreetingFunction("french")
greetInFrench("Jonathan") // prints "Bonjour, Jonathan"
```
{% endtab %}
{% endtabs %}

And this is how it builds an English-greeting function:

{% tabs fun-write-method-returns-function-16 %}
{% tab 'Scala 2 and 3' %}
```scala
val greetInEnglish = createGreetingFunction("english")
greetInEnglish("Joe") // prints "Hello, Joe"
```
{% endtab %}
{% endtabs %}

If you’re comfortable with that code---congratulations---you now know how to write methods that return functions.

Expand Down