By Developers, For Developers

Historical errata for Programming Crystal

PDF PgPaper PgTypeDescriptionFixed onComments
97TYPO

At the end of the section on modules, the variable is named ‘min’. Should this be ‘mine’ for consistancy?

2018-10-27We didn't use 'mine' elsewhere, so I'm not sure what consistency this is trying to achieve.
121TYPO

Bullet 3: if !input.includes?(’ - ’) produces an error about unterminated char literal. Double quotes?

2018-10-01
131TYPO

types_and_control_flow/argv.cr

ARGV # => (3)
..

Should be?

p ARGV # => (3)

2018-10-01
28-30ERROR

The author mentions if statements multiple times and it appears that by definition these are if expressions. The official docs also refer to if expressions under the “Control Expressions” section, see crystal-lang.org/docs/syntax_and_semantics/if.html

2018-10-01
121ERROR

“The first is the location of the standard library, which in Linux is at /opt/crystal/src .” (Also in the blue “(i) Prelude” sidebar, same page.)

This location (path) is not strictly true for all versions of Linux. On my Ubuntu 18.04, the source files are installed in /usr/share/crystal/src/ — had to track this down with the following mini-program:

  1. show_envars.cr
    #
    puts “require path: #{ENV[”CRYSTAL_PATH“]}”
    exit

These locational differences should be made explicit and discussed. Thanks! — Lorin

2018-10-27
121SUGGEST

Follow-up to erratum #83752 — In referencing source code files, it would also be good to mention repository github(dot)com(slash)crystal-lang(slash)crystal as a resource. Just a thought/suggestion.
Thanks!

2018-10-27
72SUGGEST

This phrase is not very clear because of the “(unlike Ruby)” part. Maybe remove ’ (unlike Ruby)" or rephrase it a bit?

> When you use arguments in a method’s definition, you have to enumerate them inside parentheses (unlike Ruby), like the add method in the following example

2018-10-27
87SUGGEST

> (Crystal doesn’t currently support tail call optimization for recursion, so while you can make recursion go a long way, you’ll eventually find limits to how deep you can go.)

While the language itself does not support TCO currently, it’s probably worth mentioning that LLVM might figure out TCO in some cases.

For example the error for “fact(–2)” call provided as an example on page 86 will only happen when program was not compiled with a —release flag. If you you run it with —release flag it won’t fail and will return 0. You can even change fact() to use Int64 numbers and with —release flag it will also eventually return 0, but it will take quite a while (far too long probably to wait until it exits).

2018-10-27
217TYPO

Ruby “or” converts to Crystal “||” (probably got eaten by whatever you use to generate the book)

2018-11-10We'll sort that out!
129ERROR

> Try out and explain the following command to create a strong random
password: crystal eval ‘require “secure_random”; puts SecureRandom.hex(64)’

Since Crystal 0.24.0 SecureRandom is now Random::Secure (See PR #4894 on crystal-lang/crystal repo)

require “random/secure”
puts Random::Secure.hex(64)

2018-12-14
143ERROR

> Next, you need to install the library and add it to the current project. Go to the root folder and do: $ crystal deps, or even shorter: $ shards.

In Crystal 0.25.0 crystal deps is removed, use shards (See PR #5544 on crystal-lang/crystal repo)

2018-12-14
147SUGGEST

> This proves our statement. However, if you consider memory efficiency, the inverse is true.

This phrase looks weird me. I don’t get the meaning. The fastest way to do IO allocates no additional memory, while the slowest allocates the most:

$ ./benchmark
Appending 66.71M ( 14.99ns) (± 5.54%) 0 B/op fastest
Using to_s 17.89M ( 55.88ns) (± 1.22%) 16 B/op 3.73× slower
Interpolation 3.31M (302.11ns) (± 1.08%) 192 B/op 20.15× slower

Since Crystal 0.25.0 Benchmark.ips shows allocated bytes per operation (See PR #5522 on crystal-lang/crystal repo)

2018-12-14
160SUGGEST

> For other external libraries, like for example the SDL library used in writing computer games, you need to use an attribute @[Link(“”)] that can pass flags to the linker in order to find the library.

The attribute is an old name. It seems now it should be called annotation despite being mentioned as attributes in docs.

See issue #292 in crystal-lang/crystal-book repo and PR #6063 on crystal-lang/crystal repo which introduced user defined annotations. Quote:

> This PR adds user-defined annotations to the language.
> Annotations are the old attributes:

2018-12-14
177ERROR

> You may want to add tools to deal with this. router_cr2 is a good minimal middleware for a Crystal web server, that currently outperforms3 all competi- tors.

The current results are actually not looking that great for Crystal.

This is however due to Crystal running as single process while other implementations are using multiple CPU cores. It can be improved if Crystal implementations are updated to spawn multiple processes with reuse_port: true option.

2018-12-14
191TYPO

> Crystal-clear42 implements Design by Contract using macros.

Seems misplaced under Deployment.

2018-12-14
210SUGGEST

> When overflow occurs in integer calculations Ruby converts automatically from Fixnum to Bignum. Crystal on the other hand applies simple modular arithmetic. (Overflow may yet appear in future versions of Crystal.)

It may be worth mentioning that arithmetics change seem to be coming in next release of Crystal 0.28.0 (probably in ~2 months judged by previous releases frequency)

Normal +, -, , … operators will raise on overflow (see comments at the end of PR #6223) and there are wrapping &+, &-, &, … operators already introduced in PR #6890

2018-12-14
9SUGGEST

> The Crystal standard library web server is itself very performant. In a recent test comparing web servers implemented in Node.js, Nim, Rust, and Scala, the Crystal HTTP::server handled more requests per second8 than any other server.

Not fastest currently.

Very close to Rust, Go, Python and Java, but still slower.

However it probably worth pointing out that Crystal is only using a single CPU core (1 process is running) while some other implementations like JavaScript or Go utilize multiple CPU cores.

2018-12-14
20TYPO

> You can see the variable types the compiler inferred—through type reflection—by testing with the typeof method.

In Crystal docs typeof is called an expression

2018-12-14
27SUGGEST

> You’ll use the index notation from arrays, where the key is now the index:

Maybe rephrase for clarity?

2018-12-14
51ERROR

in listing curr_conv1.cr, in lines

while input = gets
❷ break unless input

the break seems redundant.

2018-12-14
39ERROR

> Notice an important distinction between concurrent and parallel computing:
> Concurrent means that a number of fibers are running in one thread, so executing
> on one core, called coroutines in many other languages.

“Concurrent” does not care about parallelism.
It is a logical concept, not a physical concept (parallel is physical concept because it depends on “time”).
ttps://en.wikipedia.org/wiki/Concurrency_(computer_science)

original paper of coroutine (1963):
ttp://melconway.com/Home/pdf/compiler.pdf

For example (1), parallel running threads are also “concurrent” feature.

For example (2), Win32 Fiber API is system level coroutine library and you can run Fibers in cross-threads.
ttps://docs.microsoft.com/en-us/windows/desktop/api/WinBase/nf-winbase-switchtofiber
It means you can run coroutines in parallel (but maybe difficult to manage on windows).

Coroutine is one method to represent a concurrency.
This term is against Subroutine.

Thread is also another method. Maybe recent languages use “Thread” instead of coroutine.

I agree this topic is very confusing. There are many documents under misunderstanding.

2018-12-14
144ERROR

def to_csv
“#{id},#{name},#{crystal_struct}”
LOGGER.debug(“to_csv method is called”)
end

must be

def to_csv
LOGGER.debug(“to_csv method is called”)
“#{id},#{name},#{crystal_struct}”
end

2018-12-14
7TYPO

It looks like the generated PDF includes not merged conflict from the book source.

210TYPO

PDF page 210
"
Your turn 6
a. union.cr
b. class.cr
"

I was looking for the answer of the ‘Your turn 6 exercise’ but “the sample code” that I download here -> “pragprog.com/titles/crystal/source_code” does not contain files “code/foundations/union.cr” and “code/foundations/class.cr”.
I thought maybe it was somewhere else in the repository but I was unable to find any file called “union.cr” or “class.cr” in the all repository.

5136SUGGEST

The note for rubyists mentions that property is equivalent to attr_accessor, but we don’t see property used until page 57. It might be better to use property along with getter and setter in the current example.

61ERROR

“range of –127 to 128” should be “range of –128 to 127”

38SUGGEST

I don’t follow the logic that compares these two facts in the text:

> While versions of Ruby since 1.9 support fibers, the scheduling of Crystal fibers is done by Crystal itself instead of by the programmer.

38SUGGEST

I believe the paragraph “A class can also extend a module, but then its methods are called on the class” deserves at least a short example since the behaviour it describes is a common pattern :)

35TYPO

When presenting setters and getters, the text says that “You could create a method called common_name= that returns the value of @common_name”. I believe the correct name for this method would be “common_name”, since it’s returning the value of the instance variable and not assigning it.

83/84ERROR

to_i8 accepts values between –128 and 127, so the “Integer bigger than 255” error message is incorrect.

def add_to_array(arr, number)
begin
arr << number.to_i8
rescue
puts “Integer bigger than 255”
end
end

arr = [] of Int8

add_to_array(arr, “–5”)
add_to_array(arr, “150”)
add_to_array(arr, “–128”)
add_to_array(arr, “–129”)
add_to_array(arr, “256”)
p arr

produces
Integer bigger than 255
Integer bigger than 255
Integer bigger than 255
[–5_i8, –128_i8]

175ERROR

When describing on how to create a simple_kemal _app, you provided the command “crystal init” without specifying a type:

crystal init simple_kemal_app

Cannot initialize Crystal project: Invalid TYPE value: simple_kemal_app
Usage: crystal init TYPE NAME [DIR]

TYPE is one of:
lib creates library skeleton
app creates application skeleton

I think it would be worth to precise to use ‘app’ as a type of the application to create at this step.

54TYPO

On this page we see these two sentences:

Your code has access to the executable name as the constant PROGRAM_NAME .
This is “./argv” if you generated an executable with $ crystal build program.cr

For consistency, I think the second sentence should read:

This is “./argv” if you generated an executable with $ crystal build argv.cr

61SUGGEST

At the top of this page are several paragraphs starting with “Using the shortcut…” and ending with “…would not change it.” These paragraphs describe assigning values to a hash, which seems out of place in a section about tuples.

125ERROR

At the top of this page there is a sentence ending in “… E1 is the ancestor of D1 which is
the ancestor of M1 which is the ancestor of C1 which is the ancestor of Object.”

Given the previous code example, and the definition of “ancestor” in the Merriam-Webster dictionary (“one from whom a person is descended”, or “forerunner”, or “prototype”), this list seems exactly backwards. I think it should be fixed either by replacing “ancestor” with “child”, or by reversing the order of the list.

?????SUGGEST

Chapter on Creating Concurrent Code:

Although you cover the essentials, I really would like to see A WHOLE TWO CHAPTERS devoted to nothing but HOW TO USE fibers and channels in various ways. What is requested is tons of examples and different use cases. I see the same basics everywhere, but it still doesn’t register with me how to translate my Threads/Mutex knowlege from Ruby over to Crystal’s fibers & channels. Since I cannot give you a link to an article that has an EXAMPLE of what I’m talking about - contact me via the webmaster and I will send you a link to the kind of thing you need to include in future editions. Good job for the most part - I just see this as the center of Crystal upon which all other code will hinge. Flow control is everything.

1SUGGEST

In the next edition, purdy-please go into great detail about parallelism in Crystal. Devote as many chapters and pages as you need to as it is a pivotal point of coding. All other code hangs on flow control and access to shared resources. You might make comparisons to Ruby’s / JRuby’s Thread/Mutex model and so on. As of this suggestion Crystal is at version 0.33 and the book badly needs an update. Just Say’n.

47TYPO

integers outside of the range of –127 to 128.
This should be –128 to 127

Categories: