Skip to content

Commit

Permalink
Document assignment destructuring (JuliaLang#30579)
Browse files Browse the repository at this point in the history
* Document assignment destructuring
* Add reference to slurping assignment (JuliaLang#37410)
* mention swapping variables and other kinds of LHS

Co-authored-by: Jameson Nash <[email protected]>
Co-authored-by: Simeon Schaub <[email protected]>
  • Loading branch information
3 people committed Apr 22, 2021
1 parent 4f271b1 commit 2c88fb7
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 16 deletions.
5 changes: 3 additions & 2 deletions base/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ state `itr_state`. Return a `Tuple`, if `collection` itself is a `Tuple`, a subt
`AbstractVector`, if `collection` is an `AbstractArray`, a subtype of `AbstractString`
if `collection` is an `AbstractString`, and an arbitrary iterator, falling back to
`Iterators.rest(collection[, itr_state])`, otherwise.
Can be overloaded for user-defined collection types to customize the behavior of slurping
in assignments, like `a, b... = collection`.
Can be overloaded for user-defined collection types to customize the behavior of [slurping
in assignments](@ref destructuring-assignment), like `a, b... = collection`.
!!! compat "Julia 1.6"
`Base.rest` requires at least Julia 1.6.
Expand Down
103 changes: 90 additions & 13 deletions doc/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,12 +352,26 @@ Named tuples are very similar to tuples, except that fields can additionally be
using dot syntax (`x.a`) in addition to the regular indexing syntax
(`x[1]`).

## Multiple Return Values
## [Destructuring Assignment and Multiple Return Values](@id destructuring-assignment)

In Julia, one returns a tuple of values to simulate returning multiple values. However, tuples
can be created and destructured without needing parentheses, thereby providing an illusion that
multiple values are being returned, rather than a single tuple value. For example, the following
function returns a pair of values:
A comma-separated list of variables (optionally wrapped in parentheses) can appear on the
left side of an assignment: the value on the right side is _destructured_ by iterating
over and assigning to each variable in turn:

```jldoctest
julia> (a,b,c) = 1:3
1:3
julia> b
2
```

The value on the right should be an iterator (see [Iteration interface](@ref man-interface-iteration))
at least as long as the number of variables on the left (any excess elements of the
iterator are ignored).

This can be used to return multiple values from functions by returning a tuple or
other iterable value. For example, the following function returns two values:

```jldoctest foofunc
julia> function foo(a,b)
Expand All @@ -374,8 +388,7 @@ julia> foo(2,3)
(5, 6)
```

A typical usage of such a pair of return values, however, extracts each value into a variable.
Julia supports simple tuple "destructuring" that facilitates this:
Destructuring assignment extracts each value into a variable:

```jldoctest foofunc
julia> x, y = foo(2,3)
Expand All @@ -388,15 +401,79 @@ julia> y
6
```

You can also return multiple values using the `return` keyword:
Another common use is for swapping variables:
```jldoctest foofunc
julia> y, x = x, y
(5, 6)
```julia
function foo(a,b)
return a+b, a*b
end
julia> x
6
julia> y
5
```

If only a subset of the elements of the iterator are required, a common convention is to assign ignored elements to a variable
consisting of only underscores `_` (which is an otherwise invalid variable name, see
[Allowed Variable Names](@ref man-allowed-variable-names)):

```jldoctest
julia> _, _, _, d = 1:10
1:10
julia> d
4
```

Other valid left-hand side expressions can be used as elements of the assignment list, which will call [`setindex!`](@ref) or [`setproperty!`](@ref), or recursively destructure individual elements of the iterator:

```jldoctest
julia> X = zeros(3);
julia> X[1], (a,b) = (1, (2, 3))
(1, (2, 3))
julia> X
3-element Vector{Float64}:
1.0
0.0
0.0
julia> a
2
julia> b
3
```

!!! compat "Julia 1.6"
`...` with assignment requires Julia 1.6

If the last symbol in the assignment list is suffixed by `...` (known as _slurping_), then
it will be assigned a collection or lazy iterator of the remaining elements of the
right-hand side iterator:

```jldoctest
julia> a, b... = "hello"
"hello"
julia> a
'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase)
julia> b
"ello"
julia> a, b... = Iterators.map(abs2, 1:4)
Base.Generator{UnitRange{Int64}, typeof(abs2)}(abs2, 1:4)
julia> a
1
julia> b
Base.Iterators.Rest{Base.Generator{UnitRange{Int64}, typeof(abs2)}, Int64}(Base.Generator{UnitRange{Int64}, typeof(abs2)}(abs2, 1:4), 1)
```

This has the exact same effect as the previous definition of `foo`.
See [`Base.rest`](@ref) for details on the precise handling and customization for specific iterators.

## Argument destructuring

Expand Down
2 changes: 1 addition & 1 deletion doc/src/manual/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ julia> sqrt = 4
ERROR: cannot assign a value to variable Base.sqrt from module Main
```

## Allowed Variable Names
## [Allowed Variable Names](@id man-allowed-variable-names)

Variable names must begin with a letter (A-Z or a-z), underscore, or a subset of Unicode code
points greater than 00A0; in particular, [Unicode character categories](http:https://www.fileformat.info/info/unicode/category/index.htm)
Expand Down

0 comments on commit 2c88fb7

Please sign in to comment.