Skip to content

Commit fb8f690

Browse files
authored
Docs updates und restructuring (#14636)
1 parent d546036 commit fb8f690

File tree

8 files changed

+145
-126
lines changed

8 files changed

+145
-126
lines changed

lib/elixir/pages/getting-started/alias-require-and-import.md

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -156,83 +156,6 @@ end
156156

157157
Since `use` allows any code to run, we can't really know the side-effects of using a module without reading its documentation. Therefore use this function with care and only if strictly required. Don't use `use` where an `import` or `alias` would do.
158158

159-
## Understanding Aliases
160-
161-
At this point, you may be wondering: what exactly is an Elixir alias and how is it represented?
162-
163-
An alias in Elixir is a capitalized identifier (like `String`, `Keyword`, etc) which is converted to an atom during compilation. For instance, the `String` alias translates by default to the atom `:"Elixir.String"`:
164-
165-
```elixir
166-
iex> is_atom(String)
167-
true
168-
iex> to_string(String)
169-
"Elixir.String"
170-
iex> :"Elixir.String" == String
171-
true
172-
```
173-
174-
By using the `alias/2` directive, we are changing the atom the alias expands to.
175-
176-
Aliases expand to atoms because in the Erlang Virtual Machine (and consequently Elixir) modules are always represented by atoms:
177-
178-
```elixir
179-
iex> List.flatten([1, [2], 3])
180-
[1, 2, 3]
181-
iex> :"Elixir.List".flatten([1, [2], 3])
182-
[1, 2, 3]
183-
```
184-
185-
That's the mechanism we use to call Erlang modules:
186-
187-
```elixir
188-
iex> :lists.flatten([1, [2], 3])
189-
[1, 2, 3]
190-
```
191-
192-
## Module nesting
193-
194-
Now that we have talked about aliases, we can talk about nesting and how it works in Elixir. Consider the following example:
195-
196-
```elixir
197-
defmodule Foo do
198-
defmodule Bar do
199-
end
200-
end
201-
```
202-
203-
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.
204-
205-
If, later, the `Bar` module is moved outside the `Foo` module definition, it must be referenced by its full name (`Foo.Bar`) or an alias must be set using the `alias` directive discussed above.
206-
207-
**Note**: in Elixir, you don't have to define the `Foo` module before being able to define the `Foo.Bar` module, as they are effectively independent. The above could also be written as:
208-
209-
```elixir
210-
defmodule Foo.Bar do
211-
end
212-
213-
defmodule Foo do
214-
alias Foo.Bar
215-
# Can still access it as `Bar`
216-
end
217-
```
218-
219-
Aliasing a nested module does not bring parent modules into scope. Consider the following example:
220-
221-
```elixir
222-
defmodule Foo do
223-
defmodule Bar do
224-
defmodule Baz do
225-
end
226-
end
227-
end
228-
229-
alias Foo.Bar.Baz
230-
# The module `Foo.Bar.Baz` is now available as `Baz`
231-
# However, the module `Foo.Bar` is *not* available as `Bar`
232-
```
233-
234-
As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.
235-
236159
## Multi alias/import/require/use
237160

238161
It is possible to `alias`, `import`, `require`, or `use` multiple modules at once. This is particularly useful once we start nesting modules, which is very common when building Elixir applications. For example, imagine you have an application where all modules are nested under `MyApp`, you can alias the modules `MyApp.Foo`, `MyApp.Bar` and `MyApp.Baz` at once as follows:
@@ -241,4 +164,4 @@ It is possible to `alias`, `import`, `require`, or `use` multiple modules at onc
241164
alias MyApp.{Foo, Bar, Baz}
242165
```
243166

244-
With this, we have finished our tour of Elixir modules. The next topic to cover is module attributes.
167+
With this, we have finished our tour of Elixir modules.

lib/elixir/pages/getting-started/anonymous-functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Anonymous functions allow us to store and pass executable code around as if it w
99

1010
## Identifying functions and documentation
1111

12-
Before we move on to discuss anonymous functions, let's talk about how Elixir identifies named functions.
12+
Before we move on to discuss anonymous functions, let's talk about how Elixir identifies named functions – the functions defined in [modules](modules-and-functions.md).
1313

1414
Functions in Elixir are identified by both their name and their arity. The arity of a function describes the number of arguments that the function takes. From this point on we will use both the function name and its arity to describe functions throughout the documentation. `trunc/1` identifies the function which is named `trunc` and takes `1` argument, whereas `trunc/2` identifies a different (nonexistent) function with the same name but with an arity of `2`.
1515

lib/elixir/pages/getting-started/case-cond-and-if.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ iex> if nil do
100100
"This will"
101101
```
102102

103-
This is also a good opportunity to talk about variable scoping in Elixir. If any variable is declared or changed inside [`if`](`if/2`), [`case`](`case/2`), and similar constructs, the declaration and change will only be visible inside the construct. For example:
103+
### Expressions
104+
105+
Some programming languages make a distinction about expressions (code that returns a value) and statements (code that returns no value). In Elixir, there are only expressions, no statements. Everything you write in Elixir language returns some value.
106+
107+
This property allows variables to be scoped to individual blocks of code such as [`if`](`if/2`), [`case`](`case/2`), where declarations or changes are only visible inside the block. A change can't leak to outer blocks, which makes code easier to follow and understand. For example:
104108

105109
```elixir
106110
iex> x = 1
@@ -113,19 +117,22 @@ iex> x
113117
1
114118
```
115119

116-
In said cases, if you want to change a value, you must return the value from the [`if`](`if/2`):
120+
You see the return value of the [`if`](`if/2`) expression as the resulting `2` here. To retain changes made within the [`if`](`if/2`) expression on the outer block you need to assign the returned value to a variable in the outer block.
117121

118122
```elixir
119123
iex> x = 1
120124
1
121-
iex> x = if true do
122-
...> x + 1
123-
...> else
124-
...> x
125-
...> end
125+
iex> x =
126+
...> if true do
127+
...> x + 1
128+
...> else
129+
...> x
130+
...> end
126131
2
127132
```
128133

134+
With all expressions returning a value there's also no need for alternative constructs, such as ternary operators posing as an alternative to [`if`](`if/2`). Elixir does include an inline notation for [`if`](`if/2`) and, as we will [learn later](keywords-and-maps.md#do-blocks-and-keywords), it is a syntactic variation on `if`'s arguments.
135+
129136
> #### `if` is a macro {: .info}
130137
>
131138
> An interesting note regarding [`if`](`if/2`) is that it is implemented as a macro in the language: it isn't a special language construct as it would be in many languages. You can check the documentation and its source for more information.

lib/elixir/pages/getting-started/keywords-and-maps.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ iex> if true do
131131
In the example above, the `do` and `else` blocks make up a keyword list. They are nothing more than a syntax convenience on top of keyword lists. We can rewrite the above to:
132132

133133
```elixir
134-
iex> if true, do: "This will be seen", else: "This won't"
134+
iex> if(true, do: "This will be seen", else: "This won't")
135135
"This will be seen"
136136
```
137137

@@ -225,6 +225,8 @@ These operations have one large benefit in that they raise if the key does not e
225225

226226
Elixir developers typically prefer to use the `map.key` syntax and pattern matching instead of the functions in the `Map` module when working with maps because they lead to an assertive style of programming. [This blog post by José Valim](https://dashbit.co/blog/writing-assertive-code-with-elixir) provides insight and examples on how you get more concise and faster software by writing assertive code in Elixir.
227227

228+
In a further chapter you'll learn about ["Structs"](structs.md), which further enforce the idea of a map with predefined keys.
229+
228230
## Nested data structures
229231

230232
Often we will have maps inside maps, or even keywords lists inside maps, and so forth. Elixir provides conveniences for manipulating nested data structures via the `get_in/1`, `put_in/2`, `update_in/2`, and other macros giving the same conveniences you would find in imperative languages while keeping the immutable properties of the language.

lib/elixir/pages/getting-started/modules-and-functions.md

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ iex> String.length("hello")
1212
5
1313
```
1414

15-
In order to create our own modules in Elixir, we use the [`defmodule`](`defmodule/2`) macro. The first letter of the module must be in uppercase. We use the [`def`](`def/2`) macro to define functions in that module. The first letter of every function must be in lowercase (or underscore):
15+
In order to create our own modules in Elixir, we use the [`defmodule`](`defmodule/2`) macro. The first letter of an module name (an alias, as described further down) must be in uppercase. We use the [`def`](`def/2`) macro to define functions in that module. The first letter of every function must be in lowercase (or underscore):
1616

1717
```elixir
1818
iex> defmodule Math do
@@ -167,4 +167,78 @@ IO.puts(Concat.join("Hello", "world", "_")) #=> Hello_world
167167

168168
When a variable is not used by a function or a clause, we add a leading underscore (`_`) to its name to signal this intent. This rule is also covered in our [Naming Conventions](../references/naming-conventions.md#underscore-_foo) document.
169169

170-
This finishes our short introduction to modules. In the next chapters, we will learn how to use function definitions for recursion and later on explore more functionality related to modules.
170+
## Understanding Aliases
171+
172+
An alias in Elixir is a capitalized identifier (like `String`, `Keyword`, etc) which is converted to an atom during compilation. For instance, the `String` alias translates by default to the atom `:"Elixir.String"`:
173+
174+
```elixir
175+
iex> is_atom(String)
176+
true
177+
iex> to_string(String)
178+
"Elixir.String"
179+
iex> :"Elixir.String" == String
180+
true
181+
```
182+
183+
By using the `alias/2` directive, we are changing the atom the alias expands to.
184+
185+
Aliases expand to atoms because in the Erlang Virtual Machine (and consequently Elixir) modules are always represented by atoms. By namespacing
186+
those atoms elixir modules avoid conflicting with existing erlang modules.
187+
188+
```elixir
189+
iex> List.flatten([1, [2], 3])
190+
[1, 2, 3]
191+
iex> :"Elixir.List".flatten([1, [2], 3])
192+
[1, 2, 3]
193+
```
194+
195+
That's the mechanism we use to call Erlang modules:
196+
197+
```elixir
198+
iex> :lists.flatten([1, [2], 3])
199+
[1, 2, 3]
200+
```
201+
202+
## Module nesting
203+
204+
Now that we have talked about aliases, we can talk about nesting and how it works in Elixir. Consider the following example:
205+
206+
```elixir
207+
defmodule Foo do
208+
defmodule Bar do
209+
end
210+
end
211+
```
212+
213+
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.
214+
215+
If, later, the `Bar` module is moved outside the `Foo` module definition, it must be referenced by its full name (`Foo.Bar`) or an alias must be set using the `alias` directive discussed above.
216+
217+
**Note**: in Elixir, you don't have to define the `Foo` module before being able to define the `Foo.Bar` module, as they are effectively independent. The above could also be written as:
218+
219+
```elixir
220+
defmodule Foo.Bar do
221+
end
222+
223+
defmodule Foo do
224+
alias Foo.Bar
225+
# Can still access it as `Bar`
226+
end
227+
```
228+
229+
Aliasing a nested module does not bring parent modules into scope. Consider the following example:
230+
231+
```elixir
232+
defmodule Foo do
233+
defmodule Bar do
234+
defmodule Baz do
235+
end
236+
end
237+
end
238+
239+
alias Foo.Bar.Baz
240+
# The module `Foo.Bar.Baz` is now available as `Baz`
241+
# However, the module `Foo.Bar` is *not* available as `Bar`
242+
```
243+
244+
As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.

lib/elixir/pages/getting-started/pattern-matching.md

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,38 @@ iex> [0 | list]
113113
[0, 1, 2, 3]
114114
```
115115

116+
In some cases, you don't care about a particular value in a pattern. It is a common practice to bind those values to the underscore, `_`. For example, if only the head of the list matters to us, we can assign the tail to underscore:
117+
118+
```elixir
119+
iex> [head | _] = [1, 2, 3]
120+
[1, 2, 3]
121+
iex> head
122+
1
123+
```
124+
125+
The variable `_` is special in that it can never be read from. Trying to read from it gives a compile error:
126+
127+
```elixir
128+
iex> _
129+
** (CompileError) iex:1: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions
130+
```
131+
132+
If a variable is mentioned more than once in a pattern, all references must bind to the same value:
133+
134+
```elixir
135+
iex> {x, x} = {1, 1}
136+
{1, 1}
137+
iex> {x, x} = {1, 2}
138+
** (MatchError) no match of right hand side value: {1, 2}
139+
```
140+
141+
Although pattern matching allows us to build powerful constructs, its usage is limited. For instance, you cannot make function calls on the left side of a match. The following example is invalid:
142+
143+
```elixir
144+
iex> length([1, [2], 3]) = 3
145+
** (CompileError) iex:1: cannot invoke remote function :erlang.length/1 inside match
146+
```
147+
116148
Pattern matching allows developers to easily destructure data types such as tuples and lists. As we will see in the following chapters, it is one of the foundations of recursion in Elixir and applies to other types as well, like maps and binaries.
117149

118150
## The pin operator
@@ -168,36 +200,4 @@ iex> {y, 1} = {2, 2}
168200
** (MatchError) no match of right hand side value: {2, 2}
169201
```
170202

171-
If a variable is mentioned more than once in a pattern, all references must bind to the same value:
172-
173-
```elixir
174-
iex> {x, x} = {1, 1}
175-
{1, 1}
176-
iex> {x, x} = {1, 2}
177-
** (MatchError) no match of right hand side value: {1, 2}
178-
```
179-
180-
In some cases, you don't care about a particular value in a pattern. It is a common practice to bind those values to the underscore, `_`. For example, if only the head of the list matters to us, we can assign the tail to underscore:
181-
182-
```elixir
183-
iex> [head | _] = [1, 2, 3]
184-
[1, 2, 3]
185-
iex> head
186-
1
187-
```
188-
189-
The variable `_` is special in that it can never be read from. Trying to read from it gives a compile error:
190-
191-
```elixir
192-
iex> _
193-
** (CompileError) iex:1: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions
194-
```
195-
196-
Although pattern matching allows us to build powerful constructs, its usage is limited. For instance, you cannot make function calls on the left side of a match. The following example is invalid:
197-
198-
```elixir
199-
iex> length([1, [2], 3]) = 3
200-
** (CompileError) iex:1: cannot invoke remote function :erlang.length/1 inside match
201-
```
202-
203203
This finishes our introduction to pattern matching. As we will see in the next chapter, pattern matching is very common in many language constructs and they can be further augmented with guards.

lib/elixir/pages/references/patterns-and-guards.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@ iex> _
8383
** (CompileError) iex:3: invalid use of _
8484
```
8585

86+
A pinned value represents the value itself and not its – even if syntatically equal – pattern. The right hand side is compared to be equal to the pinned value:
87+
88+
```iex
89+
iex> x = %{}
90+
%{}
91+
iex> {:ok, %{}} = {:ok, %{a: 13}}
92+
{:ok, %{a: 13}}
93+
iex> {:ok, ^x} = {:ok, %{a: 13}}
94+
** (MatchError) no match of right hand side value: {:ok, %{a: 13}}
95+
(stdlib 6.2) erl_eval.erl:667: :erl_eval.expr/6
96+
iex:2: (file)
97+
```
98+
8699
### Literals (numbers and atoms)
87100

88101
Atoms and numbers (integers and floats) can appear in patterns and they are always represented as is. For example, an atom will only match an atom if they are the same atom:

lib/elixir/scripts/elixir_docs.exs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ canonical = System.fetch_env!("CANONICAL")
1717
"lib/elixir/pages/getting-started/binaries-strings-and-charlists.md",
1818
"lib/elixir/pages/getting-started/keywords-and-maps.md",
1919
"lib/elixir/pages/getting-started/modules-and-functions.md",
20-
"lib/elixir/pages/getting-started/recursion.md",
21-
"lib/elixir/pages/getting-started/enumerable-and-streams.md",
22-
"lib/elixir/pages/getting-started/processes.md",
23-
"lib/elixir/pages/getting-started/io-and-the-file-system.md",
2420
"lib/elixir/pages/getting-started/alias-require-and-import.md",
2521
"lib/elixir/pages/getting-started/module-attributes.md",
2622
"lib/elixir/pages/getting-started/structs.md",
27-
"lib/elixir/pages/getting-started/protocols.md",
23+
"lib/elixir/pages/getting-started/recursion.md",
24+
"lib/elixir/pages/getting-started/enumerable-and-streams.md",
2825
"lib/elixir/pages/getting-started/comprehensions.md",
26+
"lib/elixir/pages/getting-started/protocols.md",
2927
"lib/elixir/pages/getting-started/sigils.md",
3028
"lib/elixir/pages/getting-started/try-catch-and-rescue.md",
29+
"lib/elixir/pages/getting-started/processes.md",
30+
"lib/elixir/pages/getting-started/io-and-the-file-system.md",
3131
"lib/elixir/pages/getting-started/writing-documentation.md",
3232
"lib/elixir/pages/getting-started/optional-syntax.md",
3333
"lib/elixir/pages/getting-started/erlang-libraries.md",

0 commit comments

Comments
 (0)