Skip to content

Commit 8f7103b

Browse files
author
José Valim
committed
Update getting started guide to Elixir 1.2
1 parent eec6d39 commit 8f7103b

16 files changed

+182
-155
lines changed

_data/getting-started.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
- title: Binaries, strings and char lists
2020
slug: binaries-strings-and-char-lists
2121

22-
- title: Keywords, maps and dicts
23-
slug: maps-and-dicts
22+
- title: Keywords and maps
23+
slug: keywords-and-maps
2424

2525
- title: Modules
2626
slug: modules

_posts/2014-04-21-elixir-v0-13-0-released.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ iex> %{"other" => value} = map
6868

6969
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.
7070

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)).
7272

7373
Maps also provide special syntax for creating, accessing and updating maps with atom keys:
7474

getting-started/alias-require-and-import.markdown

+26-30
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ iex> :"Elixir.String" == String
133133
true
134134
```
135135

136-
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.
137137

138-
Aliases work as described because in the Erlang <abbr title="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 <abbr title="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:
139139

140140
```iex
141141
iex> :lists.flatten([1, [2], 3])
@@ -164,20 +164,7 @@ defmodule Foo do
164164
end
165165
```
166166

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-
defmodule Foo.Bar do
173-
end
174-
175-
defmodule Foo do
176-
alias Foo.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:
181168

182169
```elixir
183170
defmodule Elixir.Foo do
@@ -187,28 +174,23 @@ defmodule Elixir.Foo do
187174
end
188175
```
189176

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).
191180

192181
As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.
193182

194-
## `use`
183+
### Multi `alias`/`import`/`require`
195184

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:
197186

198187
```elixir
199-
defmodule Example do
200-
use Feature, option: :value
201-
end
188+
alias MyApp.{Foo, Bar, Baz}
202189
```
203190

204-
is compiled into
191+
## `use`
205192

206-
```elixir
207-
defmodule Example do
208-
require Feature
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.
212194

213195
For example, in order to write tests using the ExUnit framework, a developer should use the `ExUnit.Case` module:
214196

@@ -222,7 +204,21 @@ defmodule AssertionTest do
222204
end
223205
```
224206

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+
defmodule Example do
211+
use Feature, option: :value
212+
end
213+
```
214+
215+
is compiled into
226216

217+
```elixir
218+
defmodule Example do
219+
require Feature
220+
Feature.__using__(option: :value)
221+
end
222+
```
227223

228224
With this we are almost finishing our tour about Elixir modules. The last topic to cover is module attributes.

getting-started/basic-types.markdown

+19-7
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ Floats in Elixir are 64 bit double precision.
7272
You can invoke the `round` function to get the closest integer to a given float, or the `trunc` function to get the integer part of a float.
7373

7474
```iex
75-
iex> round 3.58
75+
iex> round(3.58)
7676
4
77-
iex> trunc 3.58
77+
iex> trunc(3.58)
7878
3
7979
```
8080

@@ -223,7 +223,7 @@ iex> add_two.(2)
223223
4
224224
```
225225

226-
Keep in mind that a variable assigned inside a function does not affect its surrounding environment:
226+
A variable assigned inside a function does not affect its surrounding environment:
227227

228228
```iex
229229
iex> x = 42
@@ -280,7 +280,21 @@ iex> [104, 101, 108, 108, 111]
280280
'hello'
281281
```
282282

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.
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+
```
284298

285299
Keep in mind single-quoted and double-quoted representations are not equivalent in Elixir as they are represented by different types:
286300

@@ -313,7 +327,7 @@ iex> tuple_size(tuple)
313327
2
314328
```
315329

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`:
317331

318332
```iex
319333
iex> tuple = {:ok, "hello"}
@@ -326,8 +340,6 @@ iex> tuple
326340

327341
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.
328342

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.
330-
331343
## Lists or tuples?
332344

333345
What is the difference between lists and tuples?

getting-started/binaries-strings-and-char-lists.markdown

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ In "Basic types", we learned about strings and used the `is_binary/1` function f
1313
```iex
1414
iex> string = "hello"
1515
"hello"
16-
iex> is_binary string
16+
iex> is_binary(string)
1717
true
1818
```
1919

@@ -32,13 +32,13 @@ Since we have code points like `ł` assigned to the number `322`, we actually ne
3232
```iex
3333
iex> string = "hełło"
3434
"hełło"
35-
iex> byte_size string
35+
iex> byte_size(string)
3636
7
37-
iex> String.length string
37+
iex> String.length(string)
3838
5
3939
```
4040

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`).
4242
4343
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 `?`:
4444

@@ -67,7 +67,7 @@ In Elixir, you can define a binary using `<<>>`:
6767
```iex
6868
iex> <<0, 1, 2, 3>>
6969
<<0, 1, 2, 3>>
70-
iex> byte_size <<0, 1, 2, 3>>
70+
iex> byte_size(<<0, 1, 2, 3>>)
7171
4
7272
```
7373

getting-started/comprehensions.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
124124

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

127-
## Results other than lists
127+
## The `:into` option
128128

129129
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.
130130

getting-started/enumerables-and-streams.markdown

+6-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ iex> Enum.reduce(1..3, 0, &+/2)
3030
6
3131
```
3232

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.
3434

3535
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.
3636

@@ -54,7 +54,7 @@ iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
5454

5555
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.
5656

57-
### The pipe operator
57+
## The pipe operator
5858

5959
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:
6060

@@ -75,9 +75,8 @@ iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7575
```
7676

7777
Streams are lazy, composable enumerables.
78-
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.
7978

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`:
8180

8281
```iex
8382
iex> 1..100_000 |> Stream.map(&(&1 * 3))
@@ -91,7 +90,9 @@ iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
9190
#Stream<[enum: 1..100000, funs: [...]]>
9291
```
9392

94-
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:
9596

9697
```iex
9798
iex> stream = Stream.cycle([1, 2, 3])

getting-started/introduction.markdown

+3-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ In this tutorial we are going to teach you the Elixir foundation, the language s
1414

1515
Our requirements are:
1616

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
1919

2020
Let's get started!
2121

@@ -52,17 +52,15 @@ After getting familiar with the basics of the language you may want to try writi
5252

5353
```elixir
5454
IO.puts "Hello world from Elixir"
55-
5655
```
5756

58-
Save it as `simple.exs` and execute it with `elixir`:
57+
Save it as `simple.exs` and execute it with `elixir`:
5958

6059
```bash
6160
$ elixir simple.exs
6261
Hello world from Elixir
6362
```
6463

65-
6664
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).
6765

6866
## Asking questions

getting-started/io-and-the-file-system.markdown

+4-4
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ A file can also be opened with `:utf8` encoding, which tells the `File` module t
5252

5353
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).
5454

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`:
5656

5757
```iex
5858
iex> File.read "hello"
@@ -82,7 +82,7 @@ However, if you expect the file to be there, the bang variation is more useful a
8282

8383
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).
8484

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`.
8686

8787
## The `Path` module
8888

@@ -95,7 +95,7 @@ iex> Path.expand("~/hello")
9595
"/Users/jose/hello"
9696
```
9797

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.
9999

100100
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 <abbr title="Virtual Machine">VM</abbr> and other curiosities.
101101

@@ -165,6 +165,6 @@ However, this requires some attention. A list may represent either a bunch of by
165165

166166
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.
167167

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".
169169

170170
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.

0 commit comments

Comments
 (0)