You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2014-04-21-elixir-v0-13-0-released.markdown
+1-1
Original file line number
Diff line number
Diff line change
@@ -68,7 +68,7 @@ iex> %{"other" => value} = map
68
68
69
69
A map pattern will match any map that has all the keys specified in the pattern. The values for the matching keys must also match. For example, `%{"hello" => world}` will match any map that has the key `"hello"` and assign the value to `world`, while `%{"hello" => "world"}` will match any map that has the key `"hello"` with value equals to `"world"`. An empty map pattern (`%{}`) will match all maps.
70
70
71
-
Developers can use the functions in the [`Map` module](/docs/stable/elixir/Map.html) to work with maps. For more information on maps and how they compare to other associative data structures in the language, please check the [Maps chapter in our new Getting Started guide](/getting-started/maps-and-dicts.html). Elixir Sips has also released two episodes that cover maps ([part 1](http://elixirsips.com/episodes/054_maps_part_1.html) and [part 2](http://elixirsips.com/episodes/055_maps_part_2.html)).
71
+
Developers can use the functions in the [`Map` module](/docs/stable/elixir/Map.html) to work with maps. For more information on maps and how they compare to other associative data structures in the language, please check the [Maps chapter in our new Getting Started guide](/getting-started/keywords-and-maps.html). Elixir Sips has also released two episodes that cover maps ([part 1](http://elixirsips.com/episodes/054_maps_part_1.html) and [part 2](http://elixirsips.com/episodes/055_maps_part_2.html)).
72
72
73
73
Maps also provide special syntax for creating, accessing and updating maps with atom keys:
By using the `alias/2` directive, we are simply changing what an alias translates to.
136
+
By using the `alias/2` directive, we are simply changing the atom the alias expands to.
137
137
138
-
Aliases work as described because in the Erlang <abbrtitle="Virtual Machine">VM</abbr> (and consequently Elixir) modules are represented by atoms. For example, that's the mechanism we use to call Erlang modules:
138
+
Aliases expand to atoms because in the Erlang <abbrtitle="Virtual Machine">VM</abbr> (and consequently Elixir) modules are always represented by atoms. For example, that's the mechanism we use to call Erlang modules:
139
139
140
140
```iex
141
141
iex> :lists.flatten([1, [2], 3])
@@ -164,20 +164,7 @@ defmodule Foo do
164
164
end
165
165
```
166
166
167
-
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.
168
-
169
-
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:
170
-
171
-
```elixir
172
-
defmoduleFoo.Bardo
173
-
end
174
-
175
-
defmoduleFoodo
176
-
aliasFoo.Bar, as:Bar
177
-
end
178
-
```
179
-
180
-
The code above is exactly the same as:
167
+
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. The code above is exactly the same as:
181
168
182
169
```elixir
183
170
defmoduleElixir.Foodo
@@ -187,28 +174,23 @@ defmodule Elixir.Foo do
187
174
end
188
175
```
189
176
190
-
**Note**: in Elixir, you don't have to define the `Foo` module before being able to define the `Foo.Bar` module, as the language translates all module names to atoms anyway. You can define arbitrarily-nested modules without defining any module in the chain (e.g., `Foo.Bar.Baz` without defining `Foo` or `Foo.Bar` first).
177
+
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.
178
+
179
+
**Note**: in Elixir, you don't have to define the `Foo` module before being able to define the `Foo.Bar` module, as the language translates all module names to atoms. You can define arbitrarily-nested modules without defining any module in the chain (e.g., `Foo.Bar.Baz` without defining `Foo` or `Foo.Bar` first).
191
180
192
181
As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.
193
182
194
-
##`use`
183
+
### Multi `alias`/`import`/`require`
195
184
196
-
Although not a directive, `use` is a macro tightly related to `require` that allows you to use a module in the current context. It `require`s the given module and then calls the `__using__/1` callback on it allowing the module to inject some code into the current context.
185
+
From Elixir v1.2, it is possible to alias, import or require 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:
197
186
198
187
```elixir
199
-
defmoduleExampledo
200
-
useFeature, option::value
201
-
end
188
+
aliasMyApp.{Foo, Bar, Baz}
202
189
```
203
190
204
-
is compiled into
191
+
## `use`
205
192
206
-
```elixir
207
-
defmoduleExampledo
208
-
requireFeature
209
-
Feature.__using__(option::value)
210
-
end
211
-
```
193
+
Although not a directive, `use` is a macro tightly related to `require` that allows you to use a module in the current context. The `use` macro is frequently used by developers to bring external functionality into the current lexical scope, often modules.
212
194
213
195
For example, in order to write tests using the ExUnit framework, a developer should use the `ExUnit.Case` module:
214
196
@@ -222,7 +204,21 @@ defmodule AssertionTest do
222
204
end
223
205
```
224
206
225
-
By calling use, a hook called `__using__` will be invoked in `ExUnit.Case` which will then do the proper setup.
207
+
Behind the scenes, `use` requires the given module and then calls the `__using__/1` callback on it allowing the module to inject some code into the current context. Generally speaking, the following module:
208
+
209
+
```elixir
210
+
defmoduleExampledo
211
+
useFeature, option::value
212
+
end
213
+
```
214
+
215
+
is compiled into
226
216
217
+
```elixir
218
+
defmoduleExampledo
219
+
requireFeature
220
+
Feature.__using__(option::value)
221
+
end
222
+
```
227
223
228
224
With this we are almost finishing our tour about Elixir modules. The last topic to cover is module attributes.
When Elixir sees a list of printable ASCII numbers, Elixir will print that as a char list (literally a list of characters). Char lists are quite common when interfacing with existing Erlang code.
283
+
When Elixir sees a list of printable ASCII numbers, Elixir will print that as a char list (literally a list of characters). Char lists are quite common when interfacing with existing Erlang code. Whenever you see a value in IEx and you are not quite sure what it is, you can use the `i/1` to retrieve information about it:
284
+
285
+
```iex
286
+
iex> i 'hello'
287
+
Term
288
+
'hello'
289
+
Data type
290
+
List
291
+
Description
292
+
...
293
+
Raw representation
294
+
[104, 101, 108, 108, 111]
295
+
Reference modules
296
+
List
297
+
```
284
298
285
299
Keep in mind single-quoted and double-quoted representations are not equivalent in Elixir as they are represented by different types:
286
300
@@ -313,7 +327,7 @@ iex> tuple_size(tuple)
313
327
2
314
328
```
315
329
316
-
It is also possible to set an element at a particular index in a tuple with `put_elem/3`:
330
+
It is also possible to put an element at a particular index in a tuple with `put_elem/3`:
317
331
318
332
```iex
319
333
iex> tuple = {:ok, "hello"}
@@ -326,8 +340,6 @@ iex> tuple
326
340
327
341
Notice that `put_elem/3` returned a new tuple. The original tuple stored in the `tuple` variable was not modified because Elixir data types are immutable. By being immutable, Elixir code is easier to reason about as you never need to worry if a particular code is mutating your data structure in place.
328
342
329
-
By being immutable, Elixir also helps eliminate common cases where concurrent code has race conditions because two different entities are trying to change a data structure at the same time.
Copy file name to clipboardExpand all lines: getting-started/binaries-strings-and-char-lists.markdown
+5-5
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ In "Basic types", we learned about strings and used the `is_binary/1` function f
13
13
```iex
14
14
iex> string = "hello"
15
15
"hello"
16
-
iex> is_binarystring
16
+
iex> is_binary(string)
17
17
true
18
18
```
19
19
@@ -32,13 +32,13 @@ Since we have code points like `ł` assigned to the number `322`, we actually ne
32
32
```iex
33
33
iex> string = "hełło"
34
34
"hełło"
35
-
iex> byte_sizestring
35
+
iex> byte_size(string)
36
36
7
37
-
iex> String.lengthstring
37
+
iex> String.length(string)
38
38
5
39
39
```
40
40
41
-
> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering `iex`.
41
+
> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering `iex` (`iex.bat`).
42
42
43
43
UTF-8 requires one byte to represent the code points `h`, `e` and `o`, but two bytes to represent `ł`. In Elixir, you can get a code point's value by using `?`:
44
44
@@ -67,7 +67,7 @@ In Elixir, you can define a binary using `<<>>`:
A bitstring generator can be mixed with "regular" enumerable generators, and supports filters as well.
126
126
127
-
## Results other than lists
127
+
## The `:into` option
128
128
129
129
In the examples above, all the comprehensions returned lists as their result. However, the result of a comprehension can be inserted into different data structures by passing the `:into` option to the comprehension.
Copy file name to clipboardExpand all lines: getting-started/enumerables-and-streams.markdown
+6-5
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ iex> Enum.reduce(1..3, 0, &+/2)
30
30
6
31
31
```
32
32
33
-
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.
33
+
The functions in the Enum module are limited to, as the name says, enumerating values in data structures. For specific operations, like inserting and updating particular elements, 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.
34
34
35
35
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.
The example above has a pipeline of operations. We start with a range and then multiply each element in the range by 3. This first operation will now create and return a list with `100_000` items. Then we keep all odd elements from the list, generating a new list, now with `50_000` items, and then we sum all entries.
56
56
57
-
###The pipe operator
57
+
## The pipe operator
58
58
59
59
The `|>` symbol used in the snippet above is the **pipe operator**: it simply takes the output from the expression on its left side and passes it as the first argument to the function call on its right side. It's similar to the Unix `|` operator. Its purpose is to highlight the flow of data being transformed by a series of functions. To see how it can make the code cleaner, have a look at the example above rewritten without using the `|>` operator:
Instead of generating intermediate lists, streams create a series of computations that are invoked only when we pass it to the `Enum` module. Streams are useful when working with large, *possibly infinite*, collections.
79
78
80
-
They are lazy because, as shown in the example above, `1..100_000 |> Stream.map(&(&1 * 3))` returns a data type, an actual stream, that represents the `map` computation over the range `1..100_000`:
79
+
In the example above, `1..100_000 |> Stream.map(&(&1 * 3))` returns a data type, an actual stream, that represents the `map` computation over the range `1..100_000`:
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:
93
+
Instead of generating intermediate lists, streams build a series of computations that are invoked only when we pass the underlying stream to the `Enum` module. Streams are useful when working with large, *possibly infinite*, collections.
94
+
95
+
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. 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:
Copy file name to clipboardExpand all lines: getting-started/introduction.markdown
+3-5
Original file line number
Diff line number
Diff line change
@@ -14,8 +14,8 @@ In this tutorial we are going to teach you the Elixir foundation, the language s
14
14
15
15
Our requirements are:
16
16
17
-
* Elixir - Version 1.0.0 onwards
18
-
* Erlang - Version 17.0 onwards
17
+
* Elixir - Version 1.2.0 onwards
18
+
* Erlang - Version 18.0 onwards
19
19
20
20
Let's get started!
21
21
@@ -52,17 +52,15 @@ After getting familiar with the basics of the language you may want to try writi
52
52
53
53
```elixir
54
54
IO.puts"Hello world from Elixir"
55
-
56
55
```
57
56
58
-
Save it as `simple.exs` and execute it with `elixir`:
57
+
Save it as `simple.exs` and execute it with `elixir`:
59
58
60
59
```bash
61
60
$ elixir simple.exs
62
61
Hello world from Elixir
63
62
```
64
63
65
-
66
64
Later on we will learn how to compile Elixir code (in [Chapter 8](/getting-started/modules.html)) and how to use the Mix build tool (in the [Mix & OTP guide](/getting-started/mix-otp/introduction-to-mix.html)). For now, let's move on to [Chapter 2](/getting-started/basic-types.html).
Copy file name to clipboardExpand all lines: getting-started/io-and-the-file-system.markdown
+4-4
Original file line number
Diff line number
Diff line change
@@ -52,7 +52,7 @@ A file can also be opened with `:utf8` encoding, which tells the `File` module t
52
52
53
53
Besides functions for opening, reading and writing files, the `File` module has many functions to work with the file system. Those functions are named after their UNIX equivalents. For example, `File.rm/1` can be used to remove files, `File.mkdir/1` to create directories, `File.mkdir_p/1` to create directories and all their parent chain. There are even `File.cp_r/2` and `File.rm_rf/1` to respectively copy and remove files and directories recursively (i.e., copying and removing the contents of the directories too).
54
54
55
-
You will also notice that functions in the `File` module have two variants: one "regular" variant and another variant which has the same name as the regular version but with a trailing bang (`!`). For example, when we read the `"hello"` file in the example above, we use `File.read/1`. Alternatively, we can use `File.read!/1`:
55
+
You will also notice that functions in the `File` module have two variants: one "regular" variant and another variant with a trailing bang (`!`). For example, when we read the `"hello"` file in the example above, we use `File.read/1`. Alternatively, we can use `File.read!/1`:
56
56
57
57
```iex
58
58
iex> File.read "hello"
@@ -82,7 +82,7 @@ However, if you expect the file to be there, the bang variation is more useful a
82
82
83
83
as, in case of an error, `File.read/1` will return `{:error, reason}` and the pattern matching will fail. You will still get the desired result (a raised error), but the message will be about the pattern which doesn't match (thus being cryptic in respect to what the error actually is about).
84
84
85
-
If you don't want to handle a possible error (i.e., you want it to bubble up), prefer using `File.read!/1`.
85
+
Therefore, if you don't want to handle the error outcomes, prefer using `File.read!/1`.
86
86
87
87
## The `Path` module
88
88
@@ -95,7 +95,7 @@ iex> Path.expand("~/hello")
95
95
"/Users/jose/hello"
96
96
```
97
97
98
-
Using functions from the `Path` module as opposed to just manipulating binaries is preferred since the `Path` module takes care of different operating systems transparently. For example, `Path.join/2` joins a path with slashes (`/`) on Unix-like systems and with backslashes (`\`) on Windows.
98
+
Using functions from the `Path` module as opposed to just manipulating binaries is preferred since the `Path` module takes care of different operating systems transparently. Finally, keep in mind that Elixir will automatically convert slahes (`/`) into backslashes (`\`) on Windows when performing file operations.
99
99
100
100
With this we have covered the main modules that Elixir provides for dealing with IO and interacting with the file system. In the next sections, we will discuss some advanced topics regarding IO. Those sections are not necessary in order to write Elixir code, so feel free to skip them, but they do provide a nice overview of how the IO system is implemented in the <abbrtitle="Virtual Machine">VM</abbr> and other curiosities.
101
101
@@ -165,6 +165,6 @@ However, this requires some attention. A list may represent either a bunch of by
165
165
166
166
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.
167
167
168
-
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.
168
+
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".
169
169
170
170
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 <abbrtitle="Virtual Machine">VM</abbr> uses processes for the underlying IO mechanisms and how to use `chardata` and `iodata` for IO operations.
0 commit comments