Skip to content
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
2 changes: 1 addition & 1 deletion getting-started/alias-require-and-import.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ end

The example above will define two modules: `Foo` and `Foo.Bar`. The second can be accessed as `Bar` inside `Foo` as long as they are in the same lexical scope.

If later the `Bar` module is moved outside the `Foo` module definition, it will need to be referenced by its full name (`Foo.Bar`) or an alias will need to be set using the `alias` directive discussed above. The `Bar` module definition will change too. This code is equivalent to the example above:
If, later, the `Bar` module is moved outside the `Foo` module definition, it will need to be referenced by its full name (`Foo.Bar`) or an alias will need to be set using the `alias` directive discussed above. The `Bar` module definition will change too. This code is equivalent to the example above:

```elixir
defmodule Foo.Bar do
Expand Down
2 changes: 1 addition & 1 deletion getting-started/binaries-strings-and-char-lists.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ iex> rest
"llo"
```

This finishes our tour of bitstrings, binaries and strings. A string is a UTF-8 encoded binary, and a binary is a bitstring where the number of bits is divisible by 8. Although this shows the flexibility Elixir provides to work with bits and bytes, 99% of the time you will be working with binaries and using the `is_binary/1` and `byte_size/1` functions.
This finishes our tour of bitstrings, binaries and strings. A string is a UTF-8 encoded binary, and a binary is a bitstring where the number of bits is divisible by 8. Although this shows the flexibility Elixir provides for working with bits and bytes, 99% of the time you will be working with binaries and using the `is_binary/1` and `byte_size/1` functions.

## Char lists

Expand Down
2 changes: 1 addition & 1 deletion getting-started/comprehensions.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
```

A bitstring generator can be mixed with the "regular" enumerable generators and provides filters as well.
A bitstring generator can be mixed with "regular" enumerable generators, and supports filters as well.

## Results other than lists

Expand Down
8 changes: 4 additions & 4 deletions getting-started/enumerables-and-streams.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ iex> Enum.reduce(1..3, 0, &+/2)
6
```

Since the Enum module was designed to work across different data types, its API is limited to functions that are useful across many data types. For specific operations, you may need to reach to modules specific to the data types. For example, if you want to insert an element at a given position in a list, you should use the `List.insert_at/3` function from [the `List` module](/docs/stable/elixir/List.html), as it would make little sense to insert a value into, for example, a range.
Since the Enum module was designed to work across different data types, its API is limited to functions that are useful across many data types. For specific operations, you may need to reach for modules specific to the data type. For example, if you want to insert an element at a given position in a list, you should use the `List.insert_at/3` function from [the `List` module](/docs/stable/elixir/List.html), as it would make little sense to insert a value into, for example, a range.

We say the functions in the `Enum` module are polymorphic because they can work with diverse data types. In particular, the functions in the `Enum` module can work with any data type that implements [the `Enumerable` protocol](/docs/stable/elixir/Enumerable.html). We are going to discuss Protocols in a later chapter, for now we are going to move on to a specific kind of enumerable called streams.

Expand Down Expand Up @@ -91,7 +91,7 @@ iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000, funs: [...]]>
```

Many functions in the `Stream` module accept any enumerable as argument and return a stream as result. It also provides functions for creating streams, possibly infinite. For example, `Stream.cycle/1` can be used to create a stream that cycles a given enumerable infinitely. Be careful to not call a function like `Enum.map/2` on such streams, as they would cycle forever:
Many functions in the `Stream` module accept any enumerable as an argument and return a stream as a result. It also provides functions for creating streams, possibly infinite. For example, `Stream.cycle/1` can be used to create a stream that cycles a given enumerable infinitely. Be careful to not call a function like `Enum.map/2` on such streams, as they would cycle forever:

```iex
iex> stream = Stream.cycle([1, 2, 3])
Expand All @@ -109,7 +109,7 @@ iex> Enum.take(stream, 3)
["h", "e", "ł"]
```

Another interesting function is `Stream.resource/3` which can be used to wrap around resources, guaranteeing they are opened right before enumeration and closed afterwards, even in case of failures. For example, we can use it to stream a file:
Another interesting function is `Stream.resource/3` which can be used to wrap around resources, guaranteeing they are opened right before enumeration and closed afterwards, even in the case of failures. For example, we can use it to stream a file:

```iex
iex> stream = File.stream!("path/to/file")
Expand All @@ -119,6 +119,6 @@ iex> Enum.take(stream, 10)

The example above will fetch the first 10 lines of the file you have selected. This means streams can be very useful for handling large files or even slow resources like network resources.

The amount of functions and functionality in [`Enum`](/docs/stable/elixir/Enum.html) and [`Stream`](/docs/stable/elixir/Stream.html) modules can be daunting at first but you will get familiar with them case by case. In particular, focus on the `Enum` module first and only move to `Stream` for the particular scenarios where laziness is required to either deal with slow resources or large, possibly infinite, collections.
The amount of functions and functionality in the [`Enum`](/docs/stable/elixir/Enum.html) and [`Stream`](/docs/stable/elixir/Stream.html) modules can be daunting at first, but you will get familiar with them case by case. In particular, focus on the `Enum` module first and only move to `Stream` for the particular scenarios where laziness is required, to either deal with slow resources or large, possibly infinite, collections.

Next we'll look at a feature central to Elixir, Processes, which allows us to write concurrent, parallel and distributed programs in an easy and understandable way.
4 changes: 2 additions & 2 deletions getting-started/introduction.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ When going through this getting started guide, it is common to have questions, a
* [elixir-talk mailing list](https://groups.google.com/group/elixir-lang-talk)
* [elixir tag on StackOverflow](https://stackoverflow.com/questions/tagged/elixir)

When doing so, remember those two tips:
When doing so, remember these two tips:

* Instead of asking "how to do X in Elixir", ask "how to solve Y in Elixir". In other words, don't ask how to implement a particular solution, instead describe the problem at hand. Stating the problem gives more context and less bias for a correct answer.

* In case things are not working as expected, please include as much information in your report, for example: your Elixir version, the code snippet and the error message along side the error stacktrace. Use sites like [Gist](https://gist.github.com/) to paste this information.
* In case things are not working as expected, please include as much information as you can in your report, for example: your Elixir version, the code snippet and the error message alongside the error stacktrace. Use sites like [Gist](https://gist.github.com/) to paste this information.
4 changes: 2 additions & 2 deletions getting-started/io-and-the-file-system.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ hello world

However, this requires some attention. A list may represent either a bunch of bytes or a bunch of characters and which one to use depends on the encoding of the IO device. If the file is opened without encoding, the file is expected to be in raw mode, and the functions in the `IO` module starting with `bin*` must be used. Those functions expect an `iodata` as argument; i.e., they expect a list of integers representing bytes and binaries to be given.

On the other hand, `:stdio` and files opened with `:utf8` encoding work with the remaining functions in the `IO` module. Those functions expect a `char_data` as argument, that is, a list of characters or strings.
On the other hand, `:stdio` and files opened with `:utf8` encoding work with the remaining functions in the `IO` module. Those functions expect a `char_data` as an argument, that is, a list of characters or strings.

Although this is a subtle difference, you only need to worry about those details if you intend to pass lists to those functions. Binaries are already represented by the underlying bytes and as such their representation is always raw.
Although this is a subtle difference, you only need to worry about these details if you intend to pass lists to those functions. Binaries are already represented by the underlying bytes and as such their representation is always raw.

This finishes our tour of IO devices and IO related functionality. We have learned about four Elixir modules - [`IO`](/docs/stable/elixir/IO.html), [`File`](/docs/stable/elixir/File.html), [`Path`](/docs/stable/elixir/Path.html) and [`StringIO`](/docs/stable/elixir/StringIO.html) - as well as how the <abbr title="Virtual Machine">VM</abbr> uses processes for the underlying IO mechanisms and how to use `chardata` and `iodata` for IO operations.
8 changes: 4 additions & 4 deletions getting-started/maps-and-dicts.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ query = from w in Weather,
select: w
```

Those features are what prompted keyword lists to be the default mechanism for passing options to functions in Elixir. In chapter 5, when we discussed the `if/2` macro, we mentioned the following syntax is supported:
These features are what prompted keyword lists to be the default mechanism for passing options to functions in Elixir. In chapter 5, when we discussed the `if/2` macro, we mentioned the following syntax is supported:

```iex
iex> if false, do: :this, else: :that
Expand All @@ -76,7 +76,7 @@ iex> if(false, [do: :this, else: :that])

In general, when the keyword list is the last argument of a function, the square brackets are optional.

In order to manipulate keyword lists, Elixir provides [the `Keyword` module](/docs/stable/elixir/Keyword.html). Remember though keyword lists are simply lists, and as such they provide the same linear performance characteristics as lists. The longer the list, the longer it will take to find a key, to count the number of items, and so on. For this reason, keyword lists are used in Elixir mainly as options. If you need to store many items or guarantee one-key associates with at maximum one-value, you should use maps instead.
In order to manipulate keyword lists, Elixir provides [the `Keyword` module](/docs/stable/elixir/Keyword.html). Remember, though, keyword lists are simply lists, and as such they provide the same linear performance characteristics as lists. The longer the list, the longer it will take to find a key, to count the number of items, and so on. For this reason, keyword lists are used in Elixir mainly as options. If you need to store many items or guarantee one-key associates with at maximum one-value, you should use maps instead.

Although we can pattern match on keyword lists, it is rarely done in practice since pattern matching on lists require the number of items and their order to match:

Expand Down Expand Up @@ -215,6 +215,6 @@ The `Dict` module allows any developer to implement their own variation of `Dict

That said, you may be wondering, which of `Keyword`, `Map` or `Dict` modules should you use in your code? The answer is: it depends.

If your code is expecting one specific data structure as argument, use the respective module as it leads to more assertive code. For example, if you expect a keyword as an argument, explicitly use the `Keyword` module instead of `Dict`. However, if your API is meant to work with any dictionary, use the `Dict` module (and make sure to write tests that pass different dict implementations as arguments).
If your code is expecting one specific data structure as an argument, use the respective module as it leads to more assertive code. For example, if you expect a keyword as an argument, explicitly use the `Keyword` module instead of `Dict`. However, if your API is meant to work with any dictionary, use the `Dict` module (and make sure to write tests that pass different dictionary implementations as arguments).

This concludes our introduction to associative data structures in Elixir. You will find out that given keyword lists and maps, you will always have the right tool to tackle problems that require associative data structures in Elixir.
This concludes our introduction to associative data structures in Elixir. You will find out that, given keyword lists and maps, you will always have the right tool to tackle problems that require associative data structures in Elixir.
2 changes: 1 addition & 1 deletion getting-started/module-attributes.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ Plug.Adapters.Cowboy.http MyPlug, []

In the example above, we have used the `plug/1` macro to connect functions that will be invoked when there is a web request. Internally, every time you call `plug/1`, the Plug library stores the given argument in a `@plugs` attribute. Just before the module is compiled, Plug runs a callback that defines a function (`call/2`) which handles http requests. This function will run all plugs inside `@plugs` in order.

In order to understand the underlying code, we'd need macros, so we will revisit this pattern in the meta-programming guide. However the focus here is exactly on how using module attributes as storage allow developers to create DSLs.
In order to understand the underlying code, we'd need macros, so we will revisit this pattern in the meta-programming guide. However the focus here is on how using module attributes as storage allows developers to create DSLs.

Another example comes from [the ExUnit framework](/docs/stable/ex_unit/) which uses module attributes as annotation and storage:

Expand Down
6 changes: 3 additions & 3 deletions getting-started/processes.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Function: #Function<20.90072148/0 in :erl_eval.expr/5>
(stdlib) proc_lib.erl:239: :proc_lib.init_p_do_apply/3
```

Besides providing better error logging, there are a couple other differences: `start/1` and `start_link/1` return `{:ok, pid}` rather than just the PID. This is what enables Tasks to be used in supervision trees. Furthermore, tasks provides convenience functions, like `Task.async/1` and `Task.await/1`, and functionality to ease distribution.
Besides providing better error logging, there are a couple of other differences: `start/1` and `start_link/1` return `{:ok, pid}` rather than just the PID. This is what enables Tasks to be used in supervision trees. Furthermore, Tasks provides convenience functions, like `Task.async/1` and `Task.await/1`, and functionality to ease distribution.

We will explore those functionalities in the ***Mix and OTP guide***, for now it is enough to remember to use Tasks to get better logging.

Expand Down Expand Up @@ -194,7 +194,7 @@ defmodule KV do
end
```

Note that the `start_link` function basically spawns a new process that runs the `loop/1` function, starting with an empty map. The `loop/1` function then waits for messages and performs the appropriate action for each message. In case of a `:get` message, it sends a message back to the caller and calls `loop/1` again, to wait for a new message. While the `:put` message actually invokes `loop/1` with a new version of the map, with the given `key` and `value` stored.
Note that the `start_link` function basically spawns a new process that runs the `loop/1` function, starting with an empty map. The `loop/1` function then waits for messages and performs the appropriate action for each message. In the case of a `:get` message, it sends a message back to the caller and calls `loop/1` again, to wait for a new message. While the `:put` message actually invokes `loop/1` with a new version of the map, with the given `key` and `value` stored.

Let's give it a try by running `iex kv.exs`:

Expand Down Expand Up @@ -231,7 +231,7 @@ iex> flush
:world
```

Using processes around state and name registering are very common patterns in Elixir applications. However, most of the time, we won't implement those patterns manually as above, but by using one of the many of the abstractions that ships with Elixir. For example, Elixir provides [agents](/docs/stable/elixir/Agent.html) which are simple abstractions around state:
Using processes around state and name registering are very common patterns in Elixir applications. However, most of the time, we won't implement those patterns manually as above, but by using one of the many abstractions that ships with Elixir. For example, Elixir provides [agents](/docs/stable/elixir/Agent.html), which are simple abstractions around state:

```iex
iex> {:ok, pid} = Agent.start_link(fn -> %{} end)
Expand Down
6 changes: 3 additions & 3 deletions getting-started/recursion.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ The first clause has a guard which says "use this definition if and only if `n`

The second definition matches the pattern and has no guard so it will be executed. It first prints our `msg` and then calls itself passing `n - 1` (`2`) as the second argument.

Our `msg` is printed and `print_multiple_times/2` is called again this time with the second argument set to `1`.
Our `msg` is printed and `print_multiple_times/2` is called again, this time with the second argument set to `1`.
Because `n` is now set to `1`, the guard in our first definition of `print_multiple_times/2` evaluates to true, and we execute this particular definition. The `msg` is printed, and there is nothing left to execute.

We defined `print_multiple_times/2` so that no matter what number is passed as the second argument it either triggers our first definition (known as a _base case_) or it triggers our second definition which will ensure that we get exactly one step closer to our base case.
We defined `print_multiple_times/2` so that, no matter what number is passed as the second argument, it either triggers our first definition (known as a _base case_) or it triggers our second definition, which will ensure that we get exactly one step closer to our base case.

## Reduce and map algorithms

Expand Down Expand Up @@ -106,7 +106,7 @@ iex math.exs
iex> Math.double_each([1, 2, 3]) #=> [2, 4, 6]
```

Here we have used recursion to traverse a list doubling each element and returning a new list. The process of taking a list and _mapping_ over it is known as a _map algorithm_.
Here we have used recursion to traverse a list, doubling each element and returning a new list. The process of taking a list and _mapping_ over it is known as a _map algorithm_.

Recursion and [tail call](https://en.wikipedia.org/wiki/Tail_call) optimization are an important part of Elixir and are commonly used to create loops. However, when programming in Elixir you will rarely use recursion as above to manipulate lists.

Expand Down
Loading