@@ -13,15 +13,34 @@ set of source lines; instead, it will always line up with one of these blocks. T
13
13
main types of scopes in Julia, * global scope* and * local scope* , the latter can be nested. The
14
14
constructs introducing scope blocks are:
15
15
16
- | Scope name | block/construct introducing this kind of scope |
17
- | :-------------------- | :-------------------------------------------------------------------------------------------------------- |
18
- | [ Global Scope] ( @ref ) | ` module ` , ` baremodule ` , at interactive prompt (REPL) |
19
- | [ Local Scope] ( @ref ) | [ Soft Local Scope] ( @ref ) : ` for ` , ` while ` , comprehensions, try-catch-finally, ` let ` |
20
- | [ Local Scope] ( @ref ) | [ Hard Local Scope] ( @ref ) : functions (either syntax, anonymous & do-blocks), ` struct ` , ` macro ` |
16
+ # [ ] (@id man-scope-table)
21
17
22
- Notably missing from this table are [ begin blocks] (@ref man-compound-expressions) and [ if blocks] (@ref man-conditional-evaluation), which do * not*
23
- introduce new scope blocks. All three types of scopes follow somewhat different rules which will
24
- be explained below as well as some extra rules for certain blocks.
18
+ * Scope blocks that may nest only in other global scope blocks:
19
+
20
+ - global scope
21
+
22
+ + module, baremodule
23
+
24
+ + at interactive prompt (REPL)
25
+
26
+ - local scope (don't allow nesting)
27
+
28
+ + type, immutable, macro
29
+
30
+ * Scope blocks which may nest anywhere (in global or local scope):
31
+
32
+ - local scope
33
+
34
+ + for, while, try-catch-finally, let
35
+
36
+ + functions (either syntax, anonymous & do-blocks)
37
+
38
+ + comprehensions, broadcast-fusing
39
+
40
+ Notably missing from this table are
41
+ [ begin blocks] (@ref man-compound-expressions) and [ if blocks] (@ref man-conditional-evaluation)
42
+ which do * not* introduce new scope blocks.
43
+ Both types of scopes follow somewhat different rules which will be explained below.
25
44
26
45
Julia uses [ lexical scoping] ( https://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping_vs._dynamic_scoping ) ,
27
46
meaning that a function's scope does not inherit from its caller's scope, but from the scope in
@@ -50,7 +69,7 @@ Thus *lexical scope* means that the scope of variables can be inferred from the
50
69
51
70
## Global Scope
52
71
53
- * Each module introduces a new global scope* , separate from the global scope of all other modules;
72
+ Each module introduces a new global scope, separate from the global scope of all other modules;
54
73
there is no all-encompassing global scope. Modules can introduce variables of other modules into
55
74
their scope through the [ using or import] (@ref modules) statements or through qualified access using the
56
75
dot-notation, i.e. each module is a so-called * namespace* . Note that variable bindings can only
@@ -87,16 +106,20 @@ Note that the interactive prompt (aka REPL) is in the global scope of the module
87
106
88
107
## Local Scope
89
108
90
- A new local scope is introduced by most code-blocks, see above table for a complete list.
91
- A local scope * usually* inherits all the variables from its parent scope, both for reading and
92
- writing. There are two subtypes of local scopes, hard and soft, with slightly different rules
93
- concerning what variables are inherited. Unlike global scopes, local scopes are not namespaces,
109
+ A new local scope is introduced by most code blocks (see above
110
+ [ table] (@ref man-scope-table) for a complete list).
111
+ A local scope inherits all the variables from a parent local scope,
112
+ both for reading and writing.
113
+ Additionally, the local scope inherits all globals that are assigned
114
+ to in its parent global scope block (if it is surrounded by a global ` if ` or ` begin ` scope).
115
+ Unlike global scopes, local scopes are not namespaces,
94
116
thus variables in an inner scope cannot be retrieved from the parent scope through some sort of
95
117
qualified access.
96
118
97
- The following rules and examples pertain to both hard and soft local scopes. A newly introduced
98
- variable in a local scope does not back-propagate to its parent scope. For example, here the
99
- ` z ` is not introduced into the top-level scope:
119
+ The following rules and examples pertain to local scopes.
120
+ A newly introduced variable in a local scope does not
121
+ back-propagate to its parent scope.
122
+ For example, here the `` z `` is not introduced into the top-level scope:
100
123
101
124
``` jldoctest
102
125
julia> for i = 1:10
@@ -110,21 +133,21 @@ ERROR: UndefVarError: z not defined
110
133
(Note, in this and all following examples it is assumed that their top-level is a global scope
111
134
with a clean workspace, for instance a newly started REPL.)
112
135
113
- Inside a local scope a variable can be forced to be a local variable using the ` local ` keyword:
136
+ Inside a local scope a variable can be forced to be a new local variable using the ` local ` keyword:
114
137
115
138
``` jldoctest
116
139
julia> x = 0;
117
140
118
141
julia> for i = 1:10
119
- local x
142
+ local x # this is also the default
120
143
x = i + 1
121
144
end
122
145
123
146
julia> x
124
147
0
125
148
```
126
149
127
- Inside a local scope a new global variable can be defined using the keyword ` global ` :
150
+ Inside a local scope a global variable can be assigned to by using the keyword ` global ` :
128
151
129
152
``` jldoctest
130
153
julia> for i = 1:10
@@ -152,37 +175,14 @@ julia> z
152
175
The ` local ` and ` global ` keywords can also be applied to destructuring assignments, e.g.
153
176
` local x, y = 1, 2 ` . In this case the keyword affects all listed variables.
154
177
155
- ### Soft Local Scope
156
-
157
- > In a soft local scope, all variables are inherited from its parent scope unless a variable is
158
- > specifically marked with the keyword ` local ` .
159
-
160
- Soft local scopes are introduced by for-loops, while-loops, comprehensions, try-catch-finally-blocks,
161
- and let-blocks. There are some extra rules for [ Let Blocks] ( @ref ) and for [ For Loops and Comprehensions] ( @ref ) .
162
-
163
- In the following example the ` x ` and ` y ` refer always to the same variables as the soft local
164
- scope inherits both read and write variables:
165
-
166
- ``` jldoctest
167
- julia> x, y = 0, 1;
168
-
169
- julia> for i = 1:10
170
- x = i + y + 1
171
- end
172
-
173
- julia> x
174
- 12
175
- ```
176
-
177
- ### Hard Local Scope
178
+ Local scopes are introduced by most block keywords,
179
+ with notable exceptions of ` begin ` and ` if ` .
178
180
179
- Hard local scopes are introduced by function definitions (in all their forms), struct type definition blocks,
180
- and macro-definitions.
181
+ In a local scope, all variables are inherited from its parent
182
+ global scope block unless:
181
183
182
- > In a hard local scope, all variables are inherited from its parent scope unless:
183
- >
184
- > * an assignment would result in a modified * global* variable, or
185
- > * a variable is specifically marked with the keyword ` local ` .
184
+ * an assignment would result in a modified * global* variable, or
185
+ * a variable is specifically marked with the keyword ` local ` .
186
186
187
187
Thus global variables are only inherited for reading but not for writing:
188
188
@@ -203,6 +203,14 @@ julia> x
203
203
204
204
An explicit ` global ` is needed to assign to a global variable:
205
205
206
+ !!! sidebar "Avoiding globals"
207
+ Avoiding changing the value of global variables is considered by many
208
+ to be a programming best-practice.
209
+ One reason for this is that remotely changing the state of global variables in other
210
+ modules should be done with care as it makes the local behavior of the program hard to reason about.
211
+ This is why the scope blocks that introduce local scope require the `` global ``
212
+ keyword to declare the intent to modify a global variable.
213
+
206
214
``` jldoctest
207
215
julia> x = 1;
208
216
@@ -216,8 +224,7 @@ julia> x
216
224
2
217
225
```
218
226
219
- Note that * nested functions* can behave differently to functions defined in the global scope as
220
- they can modify their parent scope's * local* variables:
227
+ Note that * nested functions* can modify their parent scope's * local* variables:
221
228
222
229
``` jldoctest
223
230
julia> x, y = 1, 2;
@@ -234,19 +241,40 @@ julia> function baz()
234
241
julia> baz()
235
242
22
236
243
237
- julia> x, y
244
+ julia> x, y # verify that global x and y are unchanged
238
245
(1, 2)
239
246
```
240
247
241
- The distinction between inheriting global and local variables for assignment can lead to some
242
- slight differences between functions defined in local vs. global scopes. Consider the modification
243
- of the last example by moving ` bar ` to the global scope:
248
+ The reason to allow * modifying local* variables of parent scopes in
249
+ nested functions is to allow constructing `closures
250
+ < https://en.wikipedia.org/wiki/Closure_%28computer_programming%29 > `_
251
+ which have a private state, for instance the `` state `` variable in the
252
+ following example:
253
+
254
+ ``` jldoctest
255
+ julia> let state = 0
256
+ global counter() = (state += 1)
257
+ end;
258
+
259
+ julia> counter()
260
+ 1
261
+
262
+ julia> counter()
263
+ 2
264
+ ```
265
+
266
+ See also the closures in the examples in the next two sections.
267
+
268
+ The distinction between inheriting global scope and nesting local scope
269
+ can lead to some slight differences between functions
270
+ defined in local vs. global scopes for variable assignments.
271
+ Consider the modification of the last example by moving ` bar ` to the global scope:
244
272
245
273
``` jldoctest
246
274
julia> x, y = 1, 2;
247
275
248
276
julia> function bar()
249
- x = 10 # local
277
+ x = 10 # local, no longer a closure variable
250
278
return x + y
251
279
end;
252
280
@@ -258,11 +286,11 @@ julia> function quz()
258
286
julia> quz()
259
287
14
260
288
261
- julia> x, y
289
+ julia> x, y # verify that global x and y are unchanged
262
290
(1, 2)
263
291
```
264
292
265
- Note that above subtlety does not pertain to type and macro definitions as they can only appear
293
+ Note that the above nesting rules do not pertain to type and macro definitions as they can only appear
266
294
at the global scope. There are special scoping rules concerning the evaluation of default and
267
295
keyword function arguments which are described in the [ Function section] (@ref man-functions).
268
296
@@ -292,9 +320,9 @@ they are actually called. As an example, here is an inefficient, mutually recurs
292
320
if positive integers are even or odd:
293
321
294
322
``` jldoctest
295
- julia> even(n) = n == 0 ? true : odd(n- 1);
323
+ julia> even(n) = ( n == 0) ? true : odd(n - 1);
296
324
297
- julia> odd(n) = n == 0 ? false : even(n- 1);
325
+ julia> odd(n) = ( n == 0) ? false : even(n - 1);
298
326
299
327
julia> even(3)
300
328
false
@@ -304,37 +332,8 @@ true
304
332
```
305
333
306
334
Julia provides built-in, efficient functions to test for oddness and evenness called [ ` iseven ` ] ( @ref )
307
- and [ ` isodd ` ] ( @ref ) so the above definitions should only be taken as examples.
308
-
309
- ### Hard vs. Soft Local Scope
310
-
311
- Blocks which introduce a soft local scope, such as loops, are generally used to manipulate the
312
- variables in their parent scope. Thus their default is to fully access all variables in their
313
- parent scope.
314
-
315
- Conversely, the code inside blocks which introduce a hard local scope (function, type, and macro
316
- definitions) can be executed at any place in a program. Remotely changing the state of global
317
- variables in other modules should be done with care and thus this is an opt-in feature requiring
318
- the ` global ` keyword.
319
-
320
- The reason to allow * modifying local* variables of parent scopes in nested functions is to allow
321
- constructing [ closures] ( https://en.wikipedia.org/wiki/Closure_%28computer_programming%29 ) which
322
- have a private state, for instance the ` state ` variable in the following example:
323
-
324
- ``` jldoctest
325
- julia> let state = 0
326
- global counter
327
- counter() = state += 1
328
- end;
329
-
330
- julia> counter()
331
- 1
332
-
333
- julia> counter()
334
- 2
335
- ```
336
-
337
- See also the closures in the examples in the next two sections.
335
+ and [ ` isodd ` ] ( @ref ) so the above definitions should only be considered to be examples of scope,
336
+ not efficient design.
338
337
339
338
### Let Blocks
340
339
0 commit comments