Skip to content

Commit

Permalink
some documentation improvements (JuliaLang#30697)
Browse files Browse the repository at this point in the history
fix JuliaLang#29244, document `Expr`
fix JuliaLang#30648, link `isdefined` to `isassigned`
update docstring for `macro`
fix variable scope description in manual
  • Loading branch information
JeffBezanson committed Jan 12, 2019
1 parent 88e1cb0 commit 0ecaffb
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 24 deletions.
43 changes: 38 additions & 5 deletions base/docs/basedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,13 @@ kw"primitive type"
"""
macro
`macro` defines a method to include generated code in the final body of a program. A
macro maps a tuple of arguments to a returned expression, and the resulting expression
is compiled directly rather than requiring a runtime `eval` call. Macro arguments may
include expressions, literal values, and symbols. For example:
`macro` defines a method for inserting generated code into a program.
A macro maps a sequence of argument expressions to a returned expression, and the
resulting expression is substituted directly into the program at the point where
the macro is invoked.
Macros are a way to run generated code without calling `eval`, since the generated
code instead simply becomes part of the surrounding program.
Macro arguments may include expressions, literal values, and symbols.
# Examples
```jldoctest
Expand Down Expand Up @@ -237,6 +240,34 @@ For other purposes, `:( ... )` and `quote .. end` blocks are treated identically
"""
kw"quote"

"""
Expr(head::Symbol, args...)
A type representing compound expressions in parsed julia code (ASTs).
Each expression consists of a `head` Symbol identifying which kind of
expression it is (e.g. a call, for loop, conditional statement, etc.),
and subexpressions (e.g. the arguments of a call).
The subexpressions are stored in a `Vector{Any}` field called `args`.
See the manual chapter on [Metaprogramming](@ref) and the developer
documentation [Julia ASTs](@ref).
# Examples
```jldoctest
julia> Expr(:call, :+, 1, 2)
:(1 + 2)
julia> dump(:(a ? b : c))
Expr
head: Symbol if
args: Array{Any}((3,))
1: Symbol a
2: Symbol b
3: Symbol c
```
"""
Expr

"""
'
Expand Down Expand Up @@ -1351,9 +1382,11 @@ typeof
isdefined(object, s::Symbol)
isdefined(object, index::Int)
Tests whether an assignable location is defined. The arguments can be a module and a symbol
Tests whether a global variable or object field is defined. The arguments can be a module and a symbol
or a composite object and field name (as a symbol) or index.
To test whether an array element is defined, use [`isassigned`](@ref) instead.
# Examples
```jldoctest
julia> isdefined(Base, :sum)
Expand Down
44 changes: 25 additions & 19 deletions doc/src/manual/variables-and-scoping.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ comprehensions, broadcast-fusing | local | global or local

Notably missing from this table are
[begin blocks](@ref man-compound-expressions) and [if blocks](@ref man-conditional-evaluation)
which do *not* introduce new scope blocks.
which do *not* introduce new scopes.
Both types of scopes follow somewhat different rules which will be explained below.

Julia uses [lexical scoping](https://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping_vs._dynamic_scoping),
Expand Down Expand Up @@ -97,15 +97,12 @@ A new local scope is introduced by most code blocks (see above
[table](@ref man-scope-table) for a complete list).
A local scope inherits all the variables from a parent local scope,
both for reading and writing.
Additionally, the local scope inherits all global variables that are assigned
in its parent global scope block (if it is surrounded by a global `if` or `begin` scope).
Unlike global scopes, local scopes are not namespaces,
thus variables in an inner scope cannot be retrieved from the parent scope through some sort of
qualified access.

The following rules and examples pertain to local scopes.
A newly introduced variable in a local scope does not
back-propagate to its parent scope.
A newly introduced variable in a local scope cannot be referenced by a parent scope.
For example, here the ``z`` is not introduced into the top-level scope:

```jldoctest
Expand All @@ -121,18 +118,30 @@ ERROR: UndefVarError: z not defined
In this and all following examples it is assumed that their top-level is a global scope
with a clean workspace, for instance a newly started REPL.

Inside a local scope a variable can be forced to be a new local variable using the [`local`](@ref) keyword:
Inner local scopes can, however, update variables in their parent scopes:

```jldoctest
julia> x = 0;
julia> for i = 1:1
z = i
for j = 1:1
z = 0
end
println(z)
end
0
```

julia> for i = 1:10
local x # this is also the default
Inside a local scope a variable can be forced to be a new local variable using the [`local`](@ref) keyword:

```jldoctest
julia> for i = 1:1
x = i + 1
for j = 1:1
local x = 0
end
println(x)
end
julia> x
0
2
```

Inside a local scope a global variable can be assigned to by using the keyword [`global`](@ref):
Expand Down Expand Up @@ -163,9 +172,6 @@ julia> z
The `local` and `global` keywords can also be applied to destructuring assignments, e.g.
`local x, y = 1, 2`. In this case the keyword affects all listed variables.

Local scopes are introduced by most block keywords,
with notable exceptions of `begin` and `if`.

In a local scope, all variables are inherited from its parent
global scope block unless:

Expand Down Expand Up @@ -194,8 +200,8 @@ An explicit `global` is needed to assign to a global variable:
!!! sidebar "Avoiding globals"
Avoiding changing the value of global variables is considered by many
to be a programming best-practice.
One reason for this is that remotely changing the state of global variables in other
modules should be done with care as it makes the local behavior of the program hard to reason about.
Changing the value of a global variable can cause "action at a distance",
making the behavior of a program harder to reason about.
This is why the scope blocks that introduce local scope require the `global`
keyword to declare the intent to modify a global variable.

Expand Down Expand Up @@ -233,9 +239,9 @@ julia> x, y # verify that global x and y are unchanged
(1, 2)
```

The reason to allow *modifying local* variables of parent scopes in
The reason to allow modifying local variables of parent scopes in
nested functions is to allow constructing [`closures`](https://en.wikipedia.org/wiki/Closure_%28computer_programming%29)
which have a private state, for instance the `state` variable in the
which have private state, for instance the `state` variable in the
following example:

```jldoctest
Expand Down

0 comments on commit 0ecaffb

Please sign in to comment.