By Developers, For Developers

Historical errata for Programming Elixir 1.3

PDF PgPaper PgTypeDescriptionFixed onComments
14TYPO

In the example following “Back to the match operator,” the result of `list = [ 1, 2, 3 ]` should be `[1, 2, 3]` rather than `[1, 2, 3, 4]`

2016-08-10
4TYPO

In the Installing Elixir section it reads “This book assumes you’re using at least Elixir 1.2.”. I guess it should be 1.3? :)

2016-08-10
89TYPO

s/amd/and/
The key amd key! functions work on dictionary types (Maps and structs).

2016-08-10
124TYPO

s/Trimss/Trims/

Trimss leading and trailing whitespace from str.

2016-08-10
147TYPO

The paragraph describing version “~> 0.8” and minor version “8” should be referring to “~> 0.9” and “9”.

2016-08-10
286OK

The “use/tracer.ex” code example shouldn’t have,

use Tracer

since the Tracer module hasn’t been defined.

2016-08-10That's correct. The example code shows how I'd like to be able to use it. It won't run until it is implemented. \n \nI often write my code this was—write want I want, then implement the stuff to make it work.
31TYPO

There is a mention about equality between dates of different precision, however it looks like there is a copy-paste error and only a fragment of that sentence remains.

“”"
The Time type contains an hour, minute, second, and fractions of a second.
The fraction is stored as a tuple containing microseconds and the number of
significant digits.3

of seconds means that ~T[12:34:56.0] is not equal to ~T[12:34:56.00].
“”"

2016-08-10
172SUGGEST

Whe you click de hyperlink excheck. , it contains even the last point

2016-08-10
5ERROR

In the output of the h/0 helper, it is missing the listings for c/1, nl/2, pid/1, and recompile/0.

2016-08-19
6ERROR

The output from ‘h IO.puts’ has changed from what is in the book.

2016-08-19
16TYPO

In the last paragraph, second sentence, s/with/the/. It should say, “But the second b corresponds to the value 2 on the right.”

2016-08-19
125ERROR

The examples for String.trim/2 give examples with a codepoint as the `to_trim` parameter, however this should be “!” instead of ?! I believe.

The result of running the code in 1.3 is:
iex(59)> String.trim(“!!!!”, ?!)

(FunctionClauseError) no function clause matching in String.replace_leading/3
(elixir) lib/string.ex:608: String.replace_leading(“!!!!”, 33, “”)
(elixir) lib/string.ex:848: String.trim/2
iex(59)>

2016-08-19
20SUGGEST

> There are several ways of exiting from iex—none are tidy. The easiest two are typing `Ctrl`-`C` twice or typing `Ctrl`-`G` followed by `q` and `Return`.

You can also `Ctrl`-`\\` (Control-Backslash) which is quite a bit tidier :)

2016-08-19
8TYPO

The link “[1]” that points the reader to the website where they can find the Source Code points to the old version 1.2

It should be pointing to the latest version (1.3).

2016-08-19
182172TYPO

Quote from book: “That’s where the property testing libraries come it.”

I believe that “come it” is a typo; I expect that “come in” was the intended phrase.

2016-08-19
31TYPO

“However, they are currently little more that data holders”
s/that/than/

2016-09-22
115ERROR

“In addition, Elixir defines three additional sigils, ~D, ~T, and ~N” but these three were already mentioned in the list so “in addition” doesn’t feel right.

2016-09-22
67OK

In your “How iex Displays Lists” box, I would suggest using at least 1 multibyte character in your example (where you use ‘cat’). This would clarify that the numeric values are truly code points and not single-byte values such as used in <<>> binaries. As a novice, I was asking myself are these really byte values in disguise, and, if so, how are multibyte characters handled. Using a multibyte character in the example would remove this ambiguity. Using a multibyte character might be a little more complicated for speakers of most western languages, but more precise, and more helpful for the rest of us.

2016-09-22I don't think it does display multibytes as characters in a char list.
72SUGGEST

For consistency (unless there’s a reason I’m not aware of), I suggest standardizing the name to ‘fun’, ‘func’, or ‘fn’, everywhere you refer to it. Also, in the ‘reduce’ signature, as a reader I would prefer to see ‘func’ there rather than ’’ so I could know what it is that’s being ignored.

2016-09-22
148OK

HTTPoison doesn’t return an `{:error` tuple with a second argument containing a map with a `:body` key but instead something like: `{:error, %HTTPoison.Error{id: nil, reason: :econnrefused}}`. This causes our error handler to not match: `(FunctionClauseError) no function clause matching in Issues.GitHubIssues.handle_response/1`

2016-09-23It seems to work here... \n \n~~~ elixir \niex(2)> Issues.GithubIssues.fetch("elixir-lang99", "elixir") \n{:error, \n "{\\"message\\":\\"Not Found\\",\\"documentation_url\\":\\"https://developer.github.com/v3\\"}"} \n~~~ \n
150OK

`deps` originally declared (page 147) as a list of tuples: `[ {:httpoison, “~> 0.9” } ]` but when adding Poison (page 150), it’s switched to the keyword list shorthand: `[ httpoison: “~> 0.9”, poison: “~> 2.2” ]`. Should probably either mention the switch or be consistent.

2016-09-23I kinda assumed that by the time we got here people would understand :)
85SUGGEST

The definition of the ‘may_attend_after_party’ function may be a good place to introduce the use of ‘?’ in a function name. IMHO it would be good to encourage the reader to name all methods returning boolean values with ‘?’ at the ends of their names, and doing so for all boolean methods in the book would make that clear (if that’s something you want to do).

2016-09-22
93TYPO

“is just ordered group of values” should probably be something like “is just an ordered group of values”.

2016-09-22
228TYPO

In “Move into the sequence direcory”
“direcory” -> “directory”

2016-09-23
151ERROR

In decode_response({:error, error}), this code, “{_, message} = List.keyfind(error, ”message“, 0)” produced an error.

2016-09-23
225TYPO

Within the ‘nested’ dictionary, the actor Cary Elwes’ last name is declared to be a typo (“#typo!”) when it is his first name that is a typo (“Cary”, not “Carey”). The last name is spelled correctly. This actual typo is carried through the rest of the chapter, where the first name “Carey” persists.

On the following page the example for ‘put_in’ seems to suggest that the aforementioned “Elwes” non-typo is corrected with the code, when indeed this ‘correction’ is ineffectual as the last name was already spelled properly.

2016-09-23
235TYPO

In the second paragraph, “For example, a primitive Elixir list is just ordered group of values” is missing an ‘an’:

“For example, a primitive Elixir list is just an ordered group of values”

2016-09-23
10187TYPO

There is a typo of a typo. In the example map called nested the actor Carey Elwes name appears with a comment that there is a typo which will later be fixed. However the name is not spelled incorrectly. Later, when correcting the typo the name is again spelled properly. Thus it is confusing on the next page when put_in is used to correct the spelling.

2016-09-22
208TYPO

This is not strictly a typo, but the twin terminals shown in Chapter 16 (with one above the other) are not rendered properly in the Kindle version, while they are fine in PDF. No matter what font size or orientation is chosen the box is only about 10 characters wide, so it’s unreadable.

191180TYPO

Running processes exhibits ETS tables screenshot vice versa ETS tables exhibit on the next page shows processes. The screenshots got switched.

127TYPO

After the list of sigil types is the following sentence:

> In addition, Elixir defines three additional sigils, ~D, ~T, and ~N, which con- struct dates, times, and native datetimes respectively.

The “in addition” part of this doesn’t really make sense as all three of those sigils are listed above this paragraph.

89TYPO

After the call to function `get_and_update_in`, the output shows:

%{actor: %{first: “Cary”, last: “EWES”}, …}

It looks like an L was accidentally omitted from the actor’s last name; I believe this should be

%{actor: %{first: “Cary”, last: “ELWES”}, …}

44ERROR

I think there is an error in the pin operator example, in file functions/pin.exs. I am just learning the language, but I think the pin operator makes no difference in the function behaviour. When I remove it, it works exactly the same in both cases shown in the example.

AllERROR

Code is not indented properly on Kindle.

32SUGGEST

When creating the new times on the previous page:

iex(35)> t1 = Time.new(12, 34, 56)
{:ok, ~T[12:34:56]}
iex(36)> t2 = ~T[12:34:56.78]
~T[12:34:56.78]

t1 is a tuple, while t2 is a time.

If we compare t1 directly with t2, there are more reasons for the comparison to be false than the time difference that we’re trying to emphasize in this section.

We can use a similar strategy as we had for dates, or otherwise even something like t1 == {:ok, t2}

iex(37)> t1 == {:ok, t2}
false

39SUGGEST

This could be considered either a suggestion or technical omission, but:

“Exercise: Functions-1” on page 39 does not appear to have a corresponding downloadable solution…at least, if it does, I couldn’t find the corresponding code in the directory of provided solutions. Having to work-through to discover the right solution is helpful, but not if the answer remains elusive and there is no way to look at the correct solution—that simply derails momentum. So if some of the exercise examples don’t have corresponding solutions available, providing them would be really appreciated.

Which leads to a second suggestion:

It would be helpful if the downloadable directory of solutions had chapter numbers instead of (or in addition to) the named ones that currently exist. For example, the code shown on page 40 is found inside a directory called “first_steps”…only that name appears to have no connection with the“handle_open.exs” file found within it, nor the chapter (“Anonymous Functions”) in which the example code is cited.

127TYPO

Exercise: StringsAndBinaries-7 says “Chapter 7 had an exercise about calculating sales tax on page 110.”

The page number is correct (Exercise: ListsAndRecursion-8 is on page 110); however, it is in Chapter 10, not Chapter 7.

546TYPO

The code sections, when viewed on the Kindle app on an iPad Pro, are formatted horribly: and extended bold serif font, indentation lost. Same pages look okay reading the mobi file on the Kindle Mac desktop app.

p151ERROR

The code for `def decode_response({:error, error}) do` needs to be updated. As written, an errorful call to the github API will produce something like the following:

(ArgumentError) argument error
(stdlib) :lists.keyfind(“message”, 1, %{“documentation_url” => “developer.github.com/v3”, “message” => “Not Found”})
(elixir) lib/list.ex:205: List.keyfind/4

It can be fixed by changing the first line from

{_, message} = List.keyfind(error, “message”, 0)

to

message = Map.get(error, “message”, 0)

28ERROR
  1. Keyword Lists

Example is wrong. I verified in Elixir 1.2.7 and 1.3.4 that it actually works the opposite way as described in the book!

## Example of the book doesn’t have the described output
```
iex
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> [ name: “Dave”, city: “Dallas”, likes: “Programming” ]
[name: “Dave”, city: “Dallas”, likes: “Programming”]
iex(2)>
```

## The supposed output as described in the book generates the input used in the book
```
iex
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> [ {:name, “Dave”}, {:city, “Dallas”}, {:likes, “Programming”} ]
[name: “Dave”, city: “Dallas”, likes: “Programming”]
iex(2)>
```

28SUGGEST
  1. Keyword Lists

The book only mentions that “square” brackets can be left off, but the last code example on page 28 shows that “curly” brackets are left off too. I’m also struggling to understand what is happening.

It looks:

- a list ending with a keyword lists gets converted into a list of two-value tubles, where the first tuple element is now an atom
- a tuple ending with a keyword list. The explicit square brackets of the keyword list gets added, but the keyword list remains and does not get converted into tuples with their first elements as an atom. Strange and confusing!

29ERROR

Maps

Syntax example seems to indicate that the “key” can be duplicated in a map. But this is not the case and the first value would be overwritten by the second one, something not described in the book, so I doubt this was the intention to be described.

Better example:
```
%{ key => value, key2 => value }
```

28ERROR

Keyword Lists
===

I think I finally figured out what was supposed to happen in the last keyword list example.

Wrong example from the book
—————————————————-
```
iex> [1, fred: 1, dave: 2] |> List.last |> i

  1. Data Type: Tuple
    ```

List ending with a Keyword List
——————————————————
```
iex> [1, [{:fred, 1}, {:dave, 2}]]
[1, [fred: 1, dave: 2]]
iex> v(–1) |> List.last |> i

  1. Describes it as a “keyword list”
    ```

Tuple ending with a Keyword List
———————————————————
Seeing all the curly and square brackets made it a lot easier to understand
```
iex> {1, [{:fred, 1}, {:dave, 2}]}
{1, [fred: 1, dave: 2]}
iex> v(–1) |> elem(1) |> i

  1. Describes it as a “keyword list”
    ```
194TYPO

“It then exits with a status of 99.”
Is that true? I only see “exit(:boom)”.

191ERROR

The chain.exs example should exclude the `when is_integer(final_answer)` guard clause in the `create_process` function. The bug you linked to on GitHub has long been fixed (or rather disappeared on its own) and the code works correctly without the guarg clause. The related paragraph on the next page “Why do we need this, though? It turns out there’s a bug in some versions of Elixir. 1…” should be removed too.

8TYPO

Compile and Run
——————————
Once you tire of writing …

This reads very strange. I assume it should probably rather be:

Once you get tired of writing …

1SUGGEST

This may seem bizarre, but I’m a little concerned about the title of Chapter 1: “Take the Red Pill.”

I appreciate the Matrix reference, especially given the introductions and the exhortation to the reader to take a leap of faith into Elixir. But, given events within and outside of the programming biosphere over the past year (Gamergate, the general rise of MRAs, Trump’s election, etc), the phrase “Red Pill” has been overwhelmingly co-opted by people whose voices loudly and openly seek a world less welcoming to those who are not, by and large, cis-gender, straight, white men.

Is this perhaps overthinking the problem with 4 words in a chapter heading? Maybe. But I feel strongly that in a world where language is being ever more often deployed and misused as weaponry, every word and sentence counts.

Is the tile of the chapter going to keep someone who picks up the book from reading further? Probably not. But it falls on us who would see the programming world become more open to make that path as welcoming as possible.

Anyway, just a thought, perhaps overthunk. I’m a huge fan of this book and your others.

83SUGGEST

Under “Updating a Map”, the last line reads:

“However, this syntax will not add a new key to a map. To do this, you have to use the Map.put_new/3 function”

Is it better to say Map.put considering Map.put_new is a for the case where you want to add a new entry only if that key doesn’t already exist?

70SUGGEST

The motivation for the section “Keeping Track of Values During Recursion” is a bit misleading I believe.

The opening paragraph suggests adding up the numbers in a list is a different problem to what we’ve seen so far, says that we need to keep track of the partial sum, and gives as pseudocode

sum([]) -> 0
sum([ head | tail ]) -> “total” + sum(tail)

Then it is said that there is no way to keep track of that “total” and that gives place sum/2.

Well, this introduction is not super clear I’d say, adding up a list of numbers is no different than what the book did in previous sections:

defmodule MyList do
def sum([]), do: 0
def sum([head | tail]), do: head + sum(tail)
end

and, the way things are worded, the reader could certainly interpret that is not the case.

The section might be better motivated by talking about the stack, and introducing tail-call optimization. If this concept should be rather explained when the book is more advanced (on page 190 in this edition), then you could motivate the implementation as a technique to “carry” partial results, interesting by itself, to lead to reduce/3.

Xavier

PS: By the way, the book is really good, very well-written, enjoying it a lot.

34ERROR

with-scope.exs does not seem to compile. I first tried entering it directly into iex and got ‘missing do keyword in with’. Tried to just compile the file with c and got:

(MatchError) no match of right hand side value: nil
with-scope.exs:6: (file)

Line 6 is the final line of the with before the do.

145 ERROR

Won’t Run = mix run -e ‘Issues.CLI.run([“-h”])’

Will Run = mix run -e “Issues.CLI.run([‘-h’])”
usage: issues [ count | 4 ]

Single verses double quotes for a char

146ERROR

1)- Won’t Run = mix run -e ‘Issues.CLI.run([“elixir-lang”, “elixir”])’

2)- Will Run = mix run -e “Issues.CLI.run([‘elixir-lang’, ‘elixir’])”

function Issues.GithubIssues.fetch/2 is undefined

using windows 10 cmd as admin

127TYPO

In the very last line of the page (the last line of the depicted file), the ID should be 130, not 120. That would be consistent with the example list of orders from the referenced earlier exercise.

308ERROR

It seems like the mix.exs example is missing something to add LineSigil to the deps.

73ERROR

The example for the exercise ListAndRecursion-3 shows an incorrect output: instead of ‘elixir’ it shows ?

70%TYPO

18. OTP: Supervisors / Supervisors and Workers:

>> Nothing looks different, but open lib/sequence.ex.

should be: “Nothing looks different, but open lib/sequence/application.ex.”

279SUGGEST

The last of chapter 21 says “Next we’ll look at protocols, a way of adding functionality to built-in code”,
but the next chapter 22 describes about linking modules, and the chapter 23 describes about protocols.
This sentence might not be wrong, but I don’t think it is fitted.

13TYPO

Second paragraph from the bottom, last sentence:

“Elixir calls = the match operator.”

I see two reasons to fix this. Firstly, I am not aware of multiple match operators in Elixir (I’d be interested to learn otherwise) so = is not “a” member of the group of “match operators,” it is instead “the” match operator. Secondly, the previous code example had used “a” as a variable name, and the next code example illustrates the fact that the variable “a” could fit on either side of the match operator, so seeing “= a” in the text can be slightly visually surprising.

83SUGGEST

Updating a map

Consider using Map.update for updating and inserting a new value in a map

151ERROR

The decode_response({:error, error}) line apparently expects “error” to be a list since it calls List.keyfind on it. But it’s not a list, it’s a map and this generates an “ArgumentError”; the code download handles this properly with a simple:
IO.puts “Error fetching from Github: #{error[”message“]}”
which works properly.

2121TYPO

In the section Garbage Collection in chapter 2, line number 9 -> you have used ‘divved’ which I think should be ‘divided’

173ERROR

The github identifier for ‘triq’ is out-of-date. It is now:
“triqng/triq”

38TYPO

Omission of parentheses is stated as being possible within function definitions but not within expressions (As I understand)

However, the examples given both seem to be assignments of function expressions and neither omits the use of parenthesis when being invoked:```
If your function takes no arguments, you still need the parentheses to call it:
iex> greet = fn -> IO.puts “Hello” end #Function<12.17052888 in :erl_eval.expr/5> iex> greet.()
Hello
:ok
You can, however, omit the parentheses in a function definition.
iex> f1 = fn a, b -> a * b end #Function<12.17052888 in :erl_eval.expr/5> iex> f1.(5,6)
30
iex> f2 = fn -> 99 end #Function<12.17052888 in :erl_eval.expr/5> iex> f2.()
99
`

126TYPO

iex> String.valid? “∂og” # => true, not false as indicated on p. 126

74SUGGEST

In the section “Lists of Lists” I think more emphasis should be put on the fact that the readings are lists inside of a list, and not just in the heading of the section (“List of Lists”). This confused me at first when the “def for_location_27( [time, 27, temp, rain ] | tail) do” had brackets surrounding the readings variables. I didn’t realize the head WAS a list. So then I thought the book had made a mistake when saying you could summarize from what I thought was “def for_location_27( time, _, temp, rain, temp | tail) do” to “def for_location_27( _ | tail) do” which would be incorrect if the values were in a flattened list. This confused me enough that I thought I had seen a technical error in the book and wrote up the following below, so more clarification here would probably be useful to future readers…..

(Not an accurate bug report but what I mistakenly thought, then caught:)

There appears to be a technical error / bug for the WeatherHistory example on Page 74 of the printed book. Near the bottom of the page it says, “We could have written” then “for_location_27([ [ time, , temp, rain ] | tail])“. This would be the correct way to write the third line of the WeatherHistory example. The shortened solution provided, ”def for_location_27([ | tail), do: for_location_27(tail)” because, according to the book, “in reality we don’t care what is in the head at this point,” is wrong because you need to “read in” 4 data points at a time to prevent the recursion from accidentally reading in 27 in another column, say temperature.

For instance, imagine if your test data was this:

def test_data do
[
[1366225622, 26, 15, 0.125],
[1366225623, 26, 27, 0.45],
[1366225623, 27, 15, 0.25]
]
end

Do you see the problem? The second line of data is read in like so:
time: 26
location: 27
temp: 0.45
rain: 1366225623

and the third row is effectively skipped, also.


Note the above bug isn’t really there, I just thought it was because I was confused that this was a “list of lists”, which I feel wasn’t sufficiently emphasized in the section besides the section title which I didn’t notice, or didn’t notice the significance of.

74SUGGEST

In the section “Lists of Lists” I think more emphasis should be put on the fact that the readings are lists inside of a list, and not just in the heading of the section (“List of Lists”). This confused me at first when the “def for_location_27( [time, 27, temp, rain ] | tail) do” had brackets surrounding the readings variables. I didn’t realize the head WAS a list. So then I thought the book had made a mistake when saying you could summarize from what I thought was “def for_location_27( time, _, temp, rain, temp | tail) do” to “def for_location_27( _ | tail) do” which would be incorrect if the values were in a flattened list. This confused me enough that I thought I had seen a technical error in the book and wrote up the following below, so more clarification here would probably be useful to future readers…..

(Not an accurate bug report but what I mistakenly thought, then caught:)

There appears to be a technical error / bug for the WeatherHistory example on Page 74 of the printed book. Near the bottom of the page it says, “We could have written” then “for_location_27([ [ time, , temp, rain ] | tail])“. This would be the correct way to write the third line of the WeatherHistory example. The shortened solution provided, ”def for_location_27([ | tail), do: for_location_27(tail)” because, according to the book, “in reality we don’t care what is in the head at this point,” is wrong because you need to “read in” 4 data points at a time to prevent the recursion from accidentally reading in 27 in another column, say temperature.

For instance, imagine if your test data was this:

def test_data do
[
[1366225622, 26, 15, 0.125],
[1366225623, 26, 27, 0.45],
[1366225623, 27, 15, 0.25]
]
end

Do you see the problem? The second line of data is read in like so:
time: 26
location: 27
temp: 0.45
rain: 1366225623

and the third row is effectively skipped, also.


Note the above bug isn’t really there, I just thought it was because I was confused that this was a “list of lists”, which I feel wasn’t sufficiently emphasized in the section besides the section title which I didn’t notice, or didn’t notice the significance of.

- Austin Barnes

302SUGGEST

Syntax highlighting of odds/line_sigil.exs is broken due to page break.

230ERROR

Not an error for 1.3, but mixing a new supervisor has changed in 1.4 so the text will need to be updated for the next edition.

142SUGGEST

defining the default count as a module attribute has a real disadvantage here, because later in the test, we can not import the attribute into our test, and have to hardcode `“4” in the test case.

Sure, the attribute could be exported as a 0-arity function to the test, but wouldn’t it be simpler to just define it like this?

def default_count, do: 1

and use it in the test like this:

import Issues.CLI, only: [parse_args: 1, default_count: 0]

156SUGGEST

instead of :io.format(format, fields)

using ExPrintf might be a nice choice, as most people are familiar with sprintf formats

208ERROR

On PDF page 208 it talks about how the file ~/.erlang.cookie contains the cookie / shared secret ,
but it does not say what the max length for that cookie is.

It looks like 255 characters is the max length

It might be a good idea to mention that

125ERROR

iex> String.valid? “∂og”
false

its wrong. On my iex it says true.

Categories: