Skip to content

Commit

Permalink
Merge pull request JuliaLang#23337 from JuliaLang/jb/arg_destructuring
Browse files Browse the repository at this point in the history
RFC: implement JuliaLang#6614, destructuring in formal arguments
  • Loading branch information
JeffBezanson authored Aug 31, 2017
2 parents a969c2a + afa6af1 commit ecf284d
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ New language features
* Local variables can be tested for being defined
using the new `@isdefined variable` macro ([#22281]).

* Destructuring in function arguments: when an expression such as `(x, y)` is used as
a function argument name, the argument is unpacked into local variables `x` and `y`
as in the assignment `(x, y) = arg` ([#6614]).

Language changes
----------------

Expand Down
19 changes: 19 additions & 0 deletions doc/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,25 @@ end

This has the exact same effect as the previous definition of `foo`.

## Argument destructuring

The destructuring feature can also be used within a function argument.
If a function argument name is written as a tuple (e.g. `(x, y)`) instead of just
a symbol, then an assignment `(x, y) = argument` will be inserted for you:

```julia
julia> minmax(x, y) = (y < x) ? (y, x) : (x, y)

julia> range((min, max)) = max - min

julia> range(minmax(10, 2))
8
```

Notice the extra set of parentheses in the definition of `range`.
Without those, `range` would be a two-argument function, and this example would
not work.

## Varargs Functions

It is often convenient to be able to write functions taking an arbitrary number of arguments.
Expand Down
29 changes: 29 additions & 0 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,32 @@
(loop (cadr ex) (append! (reverse (cddr ex)) vars))
`(where ,ex ,.(reverse! vars)))))

(define (lower-destructuring-args argl)
(define (check-lhs a)
(if (expr-contains-p (lambda (e) (or (decl? e) (assignment? e) (kwarg? e)))
a)
(error (string "invalid argument destructuring syntax \"" (deparse a) "\""))
a))
(define (transform-arg a)
(cond ((and (pair? a) (eq? (car a) 'tuple))
(let ((a2 (gensy)))
(cons a2 `(local (= ,(check-lhs a) ,a2)))))
((or (and (decl? a) (length= a 3)) (kwarg? a))
(let ((x (transform-arg (cadr a))))
(cons `(,(car a) ,(car x) ,(caddr a)) (cdr x))))
((vararg? a)
(let ((x (transform-arg (cadr a))))
(cons `(... ,(car x)) (cdr x))))
(else (cons a #f))))
(let loop ((argl argl)
(newa '())
(stmts '()))
(if (null? argl)
(cons (reverse newa) (reverse stmts))
(let ((a (transform-arg (car argl))))
(loop (cdr argl) (cons (car a) newa)
(if (cdr a) (cons (cdr a) stmts) stmts))))))

(define (expand-function-def- e)
(let* ((name (cadr e))
(where (if (and (pair? name) (eq? (car name) 'where))
Expand Down Expand Up @@ -1036,6 +1062,9 @@
(farg (if (decl? name)
(adj-decl name)
`(|::| |#self#| (call (core Typeof) ,name))))
(argl-stmts (lower-destructuring-args argl))
(argl (car argl-stmts))
(body (insert-after-meta body (cdr argl-stmts)))
(argl (fix-arglist
(arglist-unshift argl farg)
(and (not (any kwarg? argl)) (not (and (pair? argl)
Expand Down
26 changes: 26 additions & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5499,3 +5499,29 @@ for U in unboxedunions
end

end # module UnionOptimizations

# issue #6614, argument destructuring
f6614((x, y)) = [x, y]
@test f6614((4, 3)) == [4, 3]
g6614((x, y), (z,), (a, b)) = (x,y,z,a,b)
@test g6614((1, 2), (3,), (4, 5)) === (1,2,3,4,5)
@test_throws MethodError g6614(1, 2)
@test_throws MethodError g6614((1, 2), (3,))
@test_throws BoundsError g6614((1, 2), (3,), (1,))
h6614((x, y) = (5, 6)) = (y, x)
@test h6614() == (6, 5)
@test h6614((4, 5)) == (5, 4)
ff6614((x, y)::Tuple{Int, String}) = (x, y)
@test ff6614((1, "")) == (1, "")
@test_throws MethodError ff6614((1, 1))
gg6614((x, y)::Tuple{Int, String} = (2, " ")) = (x, y)
@test gg6614() == (2, " ")
function hh6614()
x, y = 1, 2
function g((x,y))
# make sure x and y are local
end
g((4,5))
x, y
end
@test hh6614() == (1, 2)

0 comments on commit ecf284d

Please sign in to comment.