Skip to content

Resolving TODO tags, Part 2 #1874

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 6 commits into from
May 10, 2021
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
8 changes: 6 additions & 2 deletions _overviews/scala3-book/domain-modeling-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ previous-page: domain-modeling-intro
next-page: domain-modeling-oop
---


Scala 3 provides many different constructs so we can model the world around us:

- Classes
Expand Down Expand Up @@ -411,7 +410,12 @@ For more details, see the remainder of these modeling lessons.
## Abstract classes

{% comment %}
TODO: I have some notes on when to use abstract classes, and can update this section.
LATER: If anyone wants to update this section, our comments about abstract classes and traits are on Slack. The biggest points seem to be:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LATER: If anyone wants to update this section, our comments about abstract classes and traits are on Slack. The biggest points seem to be:
LATER: If anyone wants to update this section, here are a few points that could be mentioned:

- The `super` of a trait is dynamic
- At the use site, people can mix in traits but not classes
- It remains easier to extend a class than a trait from Java, if the trait has at least a field
- Similarly, in Scala.js, a class can be imported from or exported to JavaScript. A trait cannot
- There are also some point that unrelated classes can’t be mixed together, and this can be a modeling advantage
{% endcomment %}

When you want to write a class, but you know it will have abstract members, you can either create a trait or an abstract class.
Expand Down
4 changes: 0 additions & 4 deletions _overviews/scala3-book/fp-immutable-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ Using only immutable variables raises an interesting question: If everything is
When it comes to using collections, one answer is that you don’t mutate an existing collection; instead, you apply a function to an existing collection to create a new collection.
This is where higher-order functions like `map` and `filter` come in.

{% comment %}
TODO: need a better example
{% endcomment %}

For example, imagine that you have a list of names---a `List[String]`---that are all in lowercase, and you want to find all the names that begin with the letter `"j"`, and then you want to capitalize those names.
In FP you write this code:

Expand Down
21 changes: 10 additions & 11 deletions _overviews/scala3-book/fp-pure-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ next-page: fp-functions-are-values
---


{% comment %}
TODO: Use someone else’s definition?
{% endcomment %}

Another feature that Scala offers to help you write functional code is the ability to write pure functions.
A _pure function_ can be defined like this:

- A function `f` is pure if, given the same input `x`, it always returns the same output `f(x)`
- The function’s output depends *only* on its input variables and its internal algorithm
- The function’s output depends _only_ on its input variables and its implementation
- It only computes the output and does not modify the world around it

This implies:
- It doesn’t modify its input parameters
- It doesn’t mutate any hidden state
- It doesn’t have any “back doors”: It doesn’t read data from the outside world (including the console, web services, databases, files, etc.), or write data to the outside world
Expand All @@ -42,23 +41,23 @@ These `String` methods are also pure functions:

Most methods on the Scala collections classes also work as pure functions, including `drop`, `filter`, `map`, and many more.

> In Scala, *functions* and *methods* are almost completely interchangeable, so even though we use the common industry term “pure function,” this term can be used to describe both functions and methods.
> In Scala, _functions_ and _methods_ are almost completely interchangeable, so even though we use the common industry term “pure function,” this term can be used to describe both functions and methods.
> If you’re interested in how methods can be used like functions, see the [Eta Expansion][eta] discussion.



## Examples of impure functions

Conversely, the following functions are *impure* because they violate the definition.
Conversely, the following functions are _impure_ because they violate the definition.

The `foreach` method on collections classes is impure because it’s only used for its side effects, such as printing to STDOUT.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, this is not true. It will probably be called with impure functions but List(1,2,3).foreach { () } is perfectly pure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to reword this, or is it best to just delete the foreach sentence and the three bullet points after it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to keep this discussion, here’s a stab at rewording it. FWIW, the main reason I like this discussion is that it helps people keep an eye out for methods that return Unit. I know it was something I never considered many years ago. Here’s the rewording:

While the foreach method on collections classes is technically pure, it’s typically used for side effects, such as printing to STDOUT.

A great hint that foreach might be used for side effects is that it returns the type Unit.
Because it doesn’t return anything, logically the only reason you ever call it is to achieve some side effect.
Similarly, any method that returns Unit is a candidate to be an impure function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for not following up earlier. I think your argument is perfectly sensible. Maybe it is easiest to actually say exactly that: "Keep an eye out for methods that return Unit. Since they do not return anything useful, this return type indicates that they are only called for their side effects"?


> A great hint that `foreach` is impure is that it’s method signature declares that it returns the type `Unit`.
> Because it doesn’t return anything, logically the only reason you ever call it is to achieve some side effect.
> Similarly, *any* method that returns `Unit` is going to be an impure function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like foreach above, not completely true. Unit only indicates that it might be executed for its side-effects. You can have (useless) pure methods that return Unit.

> Similarly, _any_ method that returns `Unit` is going to be an impure function.

Date and time related methods like `getDayOfWeek`, `getHour`, and `getMinute` are all impure because their output depends on something other than their input parameters.
Their results rely on some form of hidden I/O; *hidden inputs,* in these examples.
Their results rely on some form of hidden I/O; _hidden inputs,_ in these examples.

Additionally, methods that interact with the console, files, databases, web services, sensors, etc., are all impure.

Expand Down Expand Up @@ -111,8 +110,8 @@ If you understand that code, you’ll see that it meets the pure function defini

The first key point of this section is the definition of a pure function:

> A *pure function* is a function that depends only on its declared inputs and its internal algorithm to produce its output.
> It does not read any other values from “the outside world”---the world outside of the function’s scope---and it doesn’t modify any values in the outside world.
> A _pure function_ is a function that depends only on its declared inputs and its implementation to produce its output.
> It only computes its output and does not depend on or modify the outside world.

A second key point is that every real-world application interacts with the outside world.
Therefore, a simplified way to think about functional programs is that they consist of a core of pure functions that are wrapped with other functions that interact with the outside world.
Expand Down
11 changes: 3 additions & 8 deletions _overviews/scala3-book/fp-what-is-fp.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ next-page: fp-immutable-values



[Wikipedia defines *functional programming*](https://en.wikipedia.org/wiki/Functional_programming) like this:


{% comment %}
TODO: Update the CSS so this extra paragraph isn’t needed.
{% endcomment %}
[Wikipedia defines _functional programming_](https://en.wikipedia.org/wiki/Functional_programming) like this:

<blockquote>
<p>Functional programming is a programming paradigm where programs are constructed by applying and composing functions.
Expand All @@ -26,8 +21,8 @@ This allows programs to be written in a declarative and composable style, where

It can also be helpful to know that experienced functional programmers have a strong desire to see their code as math, that combining pure functions together is like combining a series of algebraic equations.

When you write functional code you feel like a mathematician, and once you understand the paradigm, you want to write pure functions that always return *values*---not exceptions or null values---so you can combine (compose) them together to create solutions.
The feeling that you’re writing math-like equations (expressions) is the driving desire that leads you to use *only* pure functions and immutable values, because that’s what you use in algebra and other forms of math.
When you write functional code you feel like a mathematician, and once you understand the paradigm, you want to write pure functions that always return _values_---not exceptions or null values---so you can combine (compose) them together to create solutions.
The feeling that you’re writing math-like equations (expressions) is the driving desire that leads you to use _only_ pure functions and immutable values, because that’s what you use in algebra and other forms of math.

Functional programming is a large topic, and there’s no simple way to condense the entire topic into one chapter, but hopefully the following sections will provide an overview of the main topics, and show some of the tools Scala provides for writing functional code.

Expand Down
22 changes: 9 additions & 13 deletions _overviews/scala3-book/fun-eta-expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ next-page: fun-hofs
---


When you look at the Scaladoc for the `map` method on Scala collections classes, you see that it’s defined to accept a *function*:
When you look at the Scaladoc for the `map` method on Scala collections classes, you see that it’s defined to accept a _function_:

```scala
def map[B](f: (A) => B): List[B]
-----------
```

Indeed, the Scaladoc clearly states, “`f` is the *function* to apply to each element.”
But despite that, somehow you can pass a *method* into `map`, and it still works:
Indeed, the Scaladoc clearly states, “`f` is the _function_ to apply to each element.”
But despite that, somehow you can pass a _method_ into `map`, and it still works:

```scala
def times10(i: Int) = i * 10 // a method
List(1, 2, 3).map(times10) // List(10,20,30)
```

Have you ever wondered how this works---how you can pass a *method* into `map`, which expects a *function*?
Have you ever wondered how this works---how you can pass a _method_ into `map`, which expects a _function_?

The technology behind this is known as *Eta Expansion*.
It converts an expression of *method type* to an equivalent expression of *function type*, and it does so seamlessly and quietly.
The technology behind this is known as _Eta Expansion_.
It converts an expression of _method type_ to an equivalent expression of _function type_, and it does so seamlessly and quietly.



Expand All @@ -37,14 +37,9 @@ NOTE: I got the following “method” definition from this page (https://dotty.
I’ve made a few changes to that description that I hope are more accurate and up to date.
{% endcomment %}

Historically, _methods_ have been a part of the definition of a class, although in Scala 3 you can now have methods outside of classes, such as [Toplevel definitions][toplevel] and [extension methods][extension].

{% comment %}
TODO: link to Toplevel definitions
{% endcomment %}

Historically, *methods* have been a part of the definition of a class, although in Scala 3 you can now have methods outside of classes, such as Toplevel definitions and [extension methods][extension].

Unlike methods, *functions* are complete objects themselves, making them first-class entities.
Unlike methods, _functions_ are complete objects themselves, making them first-class entities.

Their syntax is also different.
This example shows how to define a method and a function that perform the same task, determining if the given integer is even:
Expand Down Expand Up @@ -89,3 +84,4 @@ For more details on how this works, see the [Eta Expansion page][eta_expansion]

[eta_expansion]: {{ site.scala3ref }}/changed-features/eta-expansion.html
[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
[toplevel]: {% link _overviews/scala3-book/taste-toplevel-definitions.md %}
8 changes: 1 addition & 7 deletions _overviews/scala3-book/scala-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ val z = nums.filter(_ > 100)
.map(_ * 2)
```

Because Scala is considered to be a [strong, statically-typed language](https://heather.miller.am/blog/types-in-scala.html), you get all the benefits of static types:
As Heather Miller states, Scala is considered to be a [strong, statically-typed language](https://heather.miller.am/blog/types-in-scala.html), and you get all the benefits of static types:

- Correctness: you catch most errors at compile-time
- Great IDE support
Expand All @@ -147,12 +147,6 @@ In that list:
- Reliable code completion
{% endcomment %}

{% comment %}
In this section or the next section:
- TODO: Add a note about the benefits of the DOT calculus
- TODO: Also add a note about TASTy?
{% endcomment %}


### Expressive type system

Expand Down
8 changes: 3 additions & 5 deletions _overviews/scala3-book/scala-for-java-devs.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,17 @@ Also at a high level, the differences between Java and Scala are:
- The [Scala Native](http://www.scala-native.org) project adds low-level constructs to let you write “systems” level code, and also compiles to native executables

{% comment %}
These are several notes that came up early in the writing process, and I (Alvin) can’t really address them:
TODO: Need a good, simple way to state that Scala has a sound type system
TODO: Points to make about Scala’s consistency?
TODO: Add a point about how the type system lets you express details as desired
{% endcomment %}


### Programming level differences

Finally, these are some of the differences you’ll see every day when writing code:

{% comment %}
TODO: points to make about Scala’s consistency?
TODO: add a point about how the type system lets you express details as desired
{% endcomment %}

- Scala’s syntax is extremely consistent
- Variables and parameters are defined as `val` (immutable, like `final` in Java) or `var` (mutable)
- *Type inference* makes your code feel dynamically typed, and helps to keep your code brief
Expand Down