Errata

Introducing Elixir

Errata for Introducing Elixir

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
1
Doing Something

In Chapter 1, under the heading "Doing Something", your "Interactive Elixir" output shows an older version of Elixir than is used later on in the book:

Interactive Elixir (0.13.0) - press Ctrl+C to exit (type h() ENTER for help)

This could lead to people thinking that this book is outdated, or that they need this particular version of Elixir installed to follow along with the book. I suggest updating this version to something more modern.

Ryan Bigg  Jul 30, 2017 
PDF Page 2
bottom

Ctrl-C does not work with Werl.

Arie van Wingerden  Jul 07, 2014 
PDF Page 4
Top

Maybe it is useful to mention that Windows users should use forward slashes, to avoid escape sequences (double back slashes))

Arie van Wingerden  Jul 07, 2014 
Printed Page 11
3rd paragragh

The function returns (I like to read the -> as “yields”) the square root of 2 times a gravitational constant for Earth of 9.8 m/s, times distance (in meters).

should be...

The function returns (I like to read the -> as “yields”) the square root of 2 times the acceleration due to gravity on Earth of 9.8 m/s2, times distance (in meters).

...as the gravitation constant is the 9.8 m/s but 6.67408 × 10-11 m3 kg-1 s-2 and it should also be m/s2(meters per second square).

Samuel Vijaykumar  May 24, 2016 
PDF Page 15
bottom

It reads "When you call the c function with that file, Elixir
will execute all of the commands in it.".
However, when I put in a file called cmp.exs a line containing:
c "drop.ex"
I get errors:
iex(1)> c "cmp.exs"

== Compilation error on file cmp.exs ==
** (CompileError) cmp.exs:1: undefined function c/1
(elixir) src/elixir.erl:206: :elixir.quoted_to_erl/3
(elixir) src/elixir_lexical.erl:17: :elixir_lexical.run/3
(elixir) lib/kernel/parallel_compiler.ex:95: anonymous fn/4 in Kernel.Parall
elCompiler.spawn_compilers/8

** (exit) shutdown: 1
(elixir) lib/kernel/parallel_compiler.ex:193: Kernel.ParallelCompiler.handle
_failure/5
(elixir) lib/kernel/parallel_compiler.ex:182: Kernel.ParallelCompiler.wait_f
or_messages/8
(elixir) lib/kernel/parallel_compiler.ex:55: Kernel.ParallelCompiler.spawn_c
ompilers/3
(iex) lib/iex/helpers.ex:94: IEx.Helpers.c/2
iex(1)>

So I guess that the info supplied is at least not complete. Please provide a correct working example or leave it for later on in the book!

Arie van Wingerden  Sep 20, 2014 
PDF Page 18
Example 2-5. Using the pipe operator

I ran into an issue with this example, leaving away the parenthesis

Drop.fall_velocity(meters) |> Convert.mps_to_mph
=> 44.289078952755766

Drop.fall_velocity meters |> Convert.mps_to_mph
=> 29.612143213215756

I read about the operator precedence in the elixir documentation https://github.com/elixir-lang/elixir/blob/e48ecf47095582a946469d6b572594b4ccfd7721/lib/elixir/lib/kernel.ex#L2544-L2560

I would add a word of warning here, as many people new in elixir stumble upon this and rewrite the example like below, as suggested in the docs
meters |> Drop.fall_velocity |> Convert.mps_to_mph

So it becomes much clearer how the pipe operator works

David Mair Spiess  Jan 01, 2016 
Printed Page 30
Example 3-4

The example 3-4 is identical to example 3-3. I believe it should use pattern matching instead of guard.

Cédric Chatelain  Apr 19, 2019 
PDF Page 54
example under "Unicode"

The unicode characters, which apparently translate to "Seoul, Republic of Korea", did not reproduce in my PDF. Hence the code literally looks like this:

iex(1)> str=", " # Seoul, Republic of Korea

That is, it looks like a comma and a space. If I copy that out of the PDF and into a text editor, it looks like " , " (space, comma, space, space, space).

David Lorenzetti  Feb 16, 2014 
PDF Page 60
2nd paragraph

The text mentions in two places binary_to_integer function, while it should mention String.to_integer (which is actually used in the code at the top of the page.

Alexey Vyskubov  Nov 02, 2015 
PDF Page 62
second tip box

What exactly do you mean by "right associative, which can change the order of the resulting list"? List concatenation is associative (in mathematical sense) operation, so a ++ b ++ c is always the same, independent of the order of execution (unless, of course, there's evil with side effects inside lists in question; I don't think you're talking about such situation here).

Alexey Vyskubov  Nov 02, 2015 
PDF Page 67
Example 6.3

I'm enjoying your book -- I wrote lots of Prolog code many years ago and it's fun seeing some of these ideas in a modern context.

Your two examples at the end of Chapter 6 (ListDrop and Pascal) can be simplified. Both functions can be written without using an accumulator variable, and (more important) without having to call reverse after the main recursion is finished.

The technique is to include the output of the function as part of the pattern that describes the output list. Here is how I wrote the falls function:

defmodule ListDropNew do
def falls([]) do
[]
end

def falls([p1|pn]) do
[Drop.fall_velocity(p1) | falls(pn) ]
end
end

In Prolog the system would build the output list on the heap, with placeholders for the head and tail, and the recursive call would be transformed into tail recursion without needing to use an accumulator variable.

John Conery  Sep 09, 2015 
PDF Page 68
Mixing Lists and Tuples

iex(4)> separate_lists = List.unzip(planemos)
[[:earth,:moon,:mars],[9.8,1.6,3.71]]

List.unzip appears to have been deprecated in V1.0.0

Anonymous  Nov 19, 2014 
Printed Page 68
Mixing Lists and Tuples

Small problem of using named-value pairs without telling what it is.
Code used is this
iex(15)> fl=[:earth,:moon,:mars]
[:earth, :moon, :mars]
iex(16)> sl=[4,5,6]
[4, 5, 6]
iex(17)> List.zip([fl,sl])
[earth: 4, moon: 5, mars: 6]

I got a bit c,onfused on how the result was obtained. You know about named-value pairs in the next chapter a small hint will be good

Vishal Deepak  Sep 02, 2015 
Printed Page 68
2nd paragraph of "Mixing List and Tuples"

List.unzip/1 is no longer supported in Elixir. :lists.unzip/1 still works. But that means the code sample below does not work as printed.

Anonymous  Dec 20, 2016 
PDF Page 74
Example 6-5

I'm enjoying the book. But have a question.

defmodule Pascal do has: triangle( [ [ 0,1,0] ], .... )

I understand [0,1,0] to be the first element in [ [ 0, 1, 0] ].

So later when the code shows [ previous | _ ] = list
list being [ [ 0, 1, 0] ]

I'm thinking [ [0,1,0] | [ ] ]

The "Pattern matching" of the Sub list is what I don't understand.
I see the sublist
the first element is at address [0] [0],
second element [0] [1],
third element [0][2]

How does Pattern matching work here?

Douglas  Feb 16, 2014 
PDF Page 80
iex entry #13

Looking at
iex(13)> is_int = fn(value) -> is_integer(value) end
iex(14)> Enum.all?(list, is_int)

I was surprised you have to create is_int, as opposed to passing is_integer directly to Enum.all. Based on the example on p.77, where :math.cos(&1) got passed in to Hof.tripler, I expected to be able to do something like this:

iex> Enum.all?(list, is_integer(&1))

However, this gives an error like "unhandled &1 outside of a capture".

Similarly, I found I wasn't able to pass :math.cos(&1) to Enum.map.

It might be nice to see some clarification, somewhere, of when you can use this notation, and when you have to wrap native functions in your own. Is there a consistent rule?

David Lorenzetti  Feb 17, 2014 
PDF Page 83
iex(9) input line

c("valid_protocol.ex") should be Valid.valid?(t) instead

Anonymous  Feb 17, 2016 
PDF Page 87
last para of "The Shell is a Process"

Looking at "(x and y become bound variables, and even though they are not immutable, it is considered in the spirit of functional programming to not reuse them.)"

I ran the sample code in my shell, and then did this:
iex(15)> y

which gave the following error:
** (RuntimeError) undefined function: y/0

So it doesn't appear as if variable y got bound as a result of running the receive block.

What am I missing?

David Lorenzetti  Feb 17, 2014 
PDF Page 95
Last two paras of "Processes Talking Amongst Themselves"

Looking at "This simple example... and come in later."

I would urge a re-write of these two paragraphs. Sorry to be harsh, but these are simply not up to the quality of the rest of the writing in the book. I don't think the central point is made clearly or strongly, and I think it's due to a combination of mixed aims and vague language.

The first sentence of the first para implies the following text will compare process communication to how function calls work, but that line of argument gets dropped altogether. I would either stick with that line, or else drop it. Personally, I think it sounds like an interesting approach, so I'm going to stick with it in my examples below.

In the first paragraph, the phrase "it reports before the shell puts up the message" is not especially clear, and not an especially convincing line of argument. I'm pretty sure you mean that the report written by convert/1 shows up on the shell before the confirmatory message from send/2. However, the "it" is slightly vague. Moreover, to me, a more powerful indicator that what's happening here differs from a function call would be if you see the message from send/2 showing up before the report from convert/1-- because that shows that send() completed and returned, while the processes were still doing their thing. By the way, in my shell, that's the order I see things (that is, {:earth, 20} precedes "On earth, ..."). So personally, I would axe this approach to explaining processes, or processes-vs-functions, altogether. Talking about the order in which messages get written to the screen simply isn't the most direct way to talk about what the machine is doing.

I think one way to make the first paragraph more clear would be to be more explicit (or thorough) about how the process differs from a function call. I think there are two distinctions. First, you're sending a message to a process ID, rather than calling a function. That is, while the process was started by spawing mph_drop, by the time the message sent to pid1 gets handled, mph_drop is already out of the picture. We happen to know that the actual function that handles the message is convert/1. But the call to send() knows nothing about convert/1. All the person typing in the shell knows is that they have a PID, and they are firing off a message to it. By contrast, with a function call, the caller would invoke convert/1 by name.

The second way this differs from a function call is that, if it was a function call, send() would wait for the work to be done. Instead, send() just fires off the message and then is done. So not only does the caller of send() not know that convert/1 handles the message, in fact the caller doesn't know that anything handles the message. The message could just sit there, unhandled, for all eternity, and it wouldn't affect the shell in any significant way. After calling send(), you could enter more commands in the shell, and it would work just fine. In fact, if Elixir/Erlang has any kind of timeout function, it might be interesting/illustrative to make convert/1 use it, to delay for, say, 30 seconds, just to be able to show that you can do other things in the shell while waiting for the message to print.

This second part, I think, is the meaning of "Nothing held and waited specifically for a returned message." Again to me that language is vague. To begin with, the point of the function call isn't to get a "returned message", it's to get a message printed to the screen. I think you mean "Nothing held and waited for the function to return (i.e., to finish)." In addition, I think that the word "held" is a little too hand-wavy here-- because you haven't made explicit anywhere what it would mean for "something to hold," it is left to my imagination what you mean by the opposite, i.e., that "nothing held." I think I know what you mean, but that's only because I have a preconception about the distinction between passing messages to processes, as opposed to calling functions. If my preconception is right, I don't need to read these paragraphs. But if my preconception is wrong, I'm not being told how it is wrong, or what is right.

If you do decide to make the function vs message passing comparison explicit, then I think the second paragraph could be embedded in the detailed description of how the message passing part worked. However, I might be even more inclined to make the second paragraph come first. That is, first have a simple description of how the messages get passed around, then follow that with an explicit comparison to a function call. At least, I would try that approach (I'd have to write it out to get a feel for whether it works as well as the outline you have here, though).

Finally, I would say that the last sentence of the second paragraph also needs some work. First of all, I think you are doing real violence to the word "pass." It makes sense to me to "pass a message," but I wouldn't say of such a message that it "passed." Rather, I would say it "was passed" or "got passed." Thus, "Those messages got passed..." Even more startling is turning the passing into a noun, with "those passages." To me, a "passage" is a hallway or a page from a novel, not the successful passing of a message (or anything else). And finally, even if I am willing to go along with this creative use of language, and accept that "passage" means "the event associated with a message getting passed", I wouldn't say that "those passages came in later." Rather, I would say that "those passages happened later."

David Lorenzetti  Feb 19, 2014 
PDF Page 95
Table 8-2

Third row, middle column, should read "0.5 (16/32)", not "0.5 (32/16)".

Anonymous  Feb 19, 2016 
Printed Page 115
2nd para, near bottom of page

The text refers to the "Hide System Processes box" which doesn't seem to exist in the observer, though there is such a box in the older pman tool.

Charlie  Nov 27, 2014 
PDF Page 124
2

This looks more like a bug in 1.0.2 rather than a doc error:

Interactive Elixir (1.0.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> planemo_hash = Enum.into([earth: 9.8, moon: 1.6, mars: 3.71], HashDict.new())
#HashDict<[moon: 1.6, mars: 3.71, earth: 9.8]>
iex(2)> planemo_hash2 = HashDict.put_new(planemo_hash, :jupiter, 99.9)
#HashDict<[moon: 1.6, mars: 3.71, jupiter: 99.9, earth: 9.8]>
iex(3)> planemo_hash2 = HashDict.put_new(planemo_hash, :jupiter, 23.1)
#HashDict<[moon: 1.6, mars: 3.71, jupiter: 23.1, earth: 9.8]>
iex(4)> planemo_hash2 = HashDict.put_new(planemo_hash, :jupiter, 99.9)
#HashDict<[moon: 1.6, mars: 3.71, jupiter: 99.9, earth: 9.8]>
iex(5)>

It appears that HashDict.put_new is overwriting existing values and the text says that it should not. It seems to me that it should not as well, but I tried this on a couple of other boxes with elixir 0.14.2 and 0.15.1 and got the same results.

Anonymous  Mar 04, 2015 
PDF Page 184
1st code sample

Unterminated string "elixir-lang/ex-doc

Anonymous  Feb 21, 2016 
2126
Kindle locaton 2126, in Chapter 6, last code sample before section "Building a List of Lists"

Problem:

iex(4)> separate_lists = List.unzip(planemos) ...

List.upzip is deprecated as of v1.0.0.


Benjamin Wiley  Oct 30, 2014