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: getting_started/13.markdown
+33-18Lines changed: 33 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ defmodule Math do
20
20
end
21
21
```
22
22
23
-
From now on, any reference to `List` will automatically expand to `Math.List`. In case one wants to access the original `List`, it can be done by accessing the module via `Elixir`:
23
+
From now on, any reference to `List` will automatically expand to `Math.List`. In case one wants to access the original `List`, it can be done by prefixing the module name with `Elixir.`:
24
24
25
25
```elixir
26
26
List.flatten#=> uses Math.List.flatten
@@ -74,13 +74,13 @@ iex> Integer.is_odd(3)
74
74
true
75
75
```
76
76
77
-
In Elixir, `Integer.is_odd/1` is defined as a macro so it can be used as guards. This means that, in order to invoke `Integer.is_odd/1`, we need to first require the `Integer` module.
77
+
In Elixir, `Integer.is_odd/1` is defined as a macro so that it can be used as a guard. This means that, in order to invoke `Integer.is_odd/1`, we need to first require the `Integer` module.
78
78
79
79
In general a module does not need to be required before usage, except if we want to use the macros available in that module. An attempt to call a macro that was not loaded will raise an error. Note that like the `alias` directive, `require` is also lexically scoped. We will talk more about macros in a later chapter.
80
80
81
81
## 13.3 import
82
82
83
-
We use `import` whenever we want to easily access functions or macros from other modules without using the qualified name. For instance, if we want to use the `duplicate` function from `List` several times, we can simply import it:
83
+
We use `import` whenever we want to easily access functions or macros from other modules without using the fully-qualified name. For instance, if we want to use the `duplicate/2` function from the `List` module several times, we can simply import it:
84
84
85
85
```iex
86
86
iex> import List, only: [duplicate: 2]
@@ -89,7 +89,7 @@ iex> duplicate :ok, 3
89
89
[:ok, :ok, :ok]
90
90
```
91
91
92
-
In this case, we are importing only the function `duplicate` (with arity 2) from `List`. Although `:only` is optional, its usage is recommended. `:except` could also be given as an option.
92
+
In this case, we are importing only the function `duplicate` (with arity 2) from `List`. Although `:only` is optional, its usage is recommended in order to avoid importing all the functions of a given module inside the namespace. `:except` could also be given as an option in order to import everything in a module *except* a list of functions.
93
93
94
94
`import` also supports `:macros` and `:functions` to be given to `:only`. For example, to import all macros, one could write:
95
95
@@ -103,24 +103,24 @@ Or to import all functions, you could write:
103
103
importInteger, only::functions
104
104
```
105
105
106
-
Note that `import` is also **lexically scoped**, this means we can import specific macros inside specific functions:
106
+
Note that `import` is **lexically scoped** too. This means that we can import specific macros or functions inside function definitions:
107
107
108
108
```elixir
109
109
defmoduleMathdo
110
110
defsome_functiondo
111
111
importList, only: [duplicate:2]
112
-
# call duplicate
112
+
duplicate(:ok, 10)
113
113
end
114
114
end
115
115
```
116
116
117
117
In the example above, the imported `List.duplicate/2` is only visible within that specific function. `duplicate/2` won't be available in any other function in that module (or any other module for that matter).
118
118
119
-
Note that importing a module automatically requires it.
119
+
Note that `import`ing a module automatically `require`s it.
120
120
121
121
## 13.4 Aliases
122
122
123
-
At this point, you may be wondering, what exactly an Elixir alias is and how it is represented?
123
+
At this point you may be wondering: what exactly an Elixir alias is and how is it represented?
124
124
125
125
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"`:
126
126
@@ -129,16 +129,16 @@ iex> is_atom(String)
129
129
true
130
130
iex> to_string(String)
131
131
"Elixir.String"
132
-
iex> :"Elixir.String"
133
-
String
132
+
iex> :"Elixir.String" == String
133
+
true
134
134
```
135
135
136
136
By using the `alias/2` directive, we are simply changing what an alias translates to.
137
137
138
-
Aliases work as described because in the Erlang VM (and consequently Elixir), modules are represented by atoms. For example, that's the mechanism we use to call Erlang modules:
138
+
Aliases work as described because in the Erlang VM (and consequently Elixir) modules are represented by atoms. For example, that's the mechanism we use to call Erlang modules:
139
139
140
140
```iex
141
-
iex> :lists.flatten([1,[2],3])
141
+
iex> :lists.flatten([1,[2],3])
142
142
[1, 2, 3]
143
143
```
144
144
@@ -147,11 +147,11 @@ This is also the mechanism that allows us to dynamically call a given function i
147
147
```iex
148
148
iex> mod = :lists
149
149
:lists
150
-
iex> mod.flatten([1,[2],3])
151
-
[1,2,3]
150
+
iex> mod.flatten([1,[2],3])
151
+
[1, 2, 3]
152
152
```
153
153
154
-
In other words, we are simply calling the function `flatten` on the atom `:lists`.
154
+
We are simply calling the function `flatten` on the atom `:lists`.
155
155
156
156
## 13.5 Nesting
157
157
@@ -164,9 +164,20 @@ 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. If later the developer decides to move `Bar` to another file, it will need to be referenced by its full name (`Foo.Bar`) or an alias needs to be set using the `alias` directive discussed above.
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
+
```
168
179
169
-
In other words, the code above is exactly the same as:
180
+
The code above is exactly the same as:
170
181
171
182
```elixir
172
183
defmoduleElixir.Foodo
@@ -176,4 +187,8 @@ defmodule Elixir.Foo do
176
187
end
177
188
```
178
189
179
-
As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic. With this we are almost finishing our tour about Elixir modules, the last topic to cover is module attributes.
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).
191
+
192
+
As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.
193
+
194
+
With this we are almost finishing our tour about Elixir modules. The last topic to cover is module attributes.
0 commit comments