Skip to content

Commit

Permalink
support dots for unary operators (#20249)
Browse files Browse the repository at this point in the history
* support dots for unary operators (closes #14161)
* docs for unary dot operators
* work around #20249
  • Loading branch information
stevengj authored and StefanKarpinski committed Feb 2, 2017
1 parent 3c20d76 commit 3aecb67
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 12 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Language changes
the `broadcast` call `(⨳).(a, b)`. Hence, one no longer defines methods
for `.*` etcetera. This also means that "dot operations" automatically
fuse into a single loop, along with other dot calls `f.(x)`. ([#17623])
Similarly for unary operators ([#20249]).

* Newly defined methods are no longer callable from the same dynamic runtime
scope they were defined in ([#17057]).
Expand Down
2 changes: 1 addition & 1 deletion doc/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ julia> @. X = sin(cos(Y)) # equivalent to X .= sin.(cos.(Y))
-0.608083
```

Operators like `.*` are handled with the same mechanism:
Binary (or unary) operators like `.+` are handled with the same mechanism:
they are equivalent to `broadcast` calls and are fused with other nested "dot" calls.
`X .+= Y` etcetera is equivalent to `X .= X .+ Y` and results in a fused in-place assignment;
see also [dot operators](@ref man-dot-operators).
Expand Down
4 changes: 3 additions & 1 deletion doc/src/manual/mathematical-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ to perform `^` element-by-element on arrays. For example,
`[1,2,3] ^ 3` is not defined, since there is no standard
mathematical meaning to "cubing" an array, but `[1,2,3] .^ 3`
is defined as computing the elementwise
(or "vectorized") result `[1^3, 2^3, 3^3]`.
(or "vectorized") result `[1^3, 2^3, 3^3]`. Similarly for unary
operators like `!` or ``, there is a corresponding `.√` that
applies the operator elementwise.

```jldoctest
julia> [1,2,3] .^ 3
Expand Down
13 changes: 7 additions & 6 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@
t))
(define (operator-precedence op) (get prec-table op 0))

(define unary-ops '(+ - ! ¬ ~ |<:| |>:| √ ∛ ∜))
(define unary-ops (append! '(|<:| |>:| ~)
(add-dots '(+ - ! ¬ √ ∛ ∜))))

; operators that are both unary and binary
(define unary-and-binary-ops '(+ - $ & ~))
(define unary-and-binary-ops '(+ - $ & ~ |.+| |.-|))

; operators that are special forms, not function names
(define syntactic-operators
Expand All @@ -93,9 +94,9 @@

(define operators
(filter (lambda (x) (not (is-word-operator? x)))
(list* '~ '! '-> '√ '∛ '∜ ctrans-op trans-op vararg-op
(delete-duplicates
(apply append (map eval prec-names))))))
(delete-duplicates
(list* '-> ctrans-op trans-op vararg-op
(append unary-ops (apply append (map eval prec-names)))))))

(define op-chars
(delete-duplicates
Expand Down Expand Up @@ -200,7 +201,7 @@
(loop newop (peek-char port)))
str))
str))))
(if (or (equal? str "--") (equal? str ".!"))
(if (equal? str "--")
(error (string "invalid operator \"" str "\"")))
(string->symbol str))))

Expand Down
5 changes: 5 additions & 0 deletions test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ let g = Int[], ⊕ = (a,b) -> let c=a+2b; push!(g, c); c; end
@test g == [21,221,24,424,27,627] # test for loop fusion
end

# Fused unary operators
@test .√[3,4,5] == sqrt.([3,4,5])
@test .![true, true, false] == [false, false, true]
@test .-[1,2,3] == -[1,2,3] == .+[-1,-2,-3] == [-1,-2,-3]

# PR 16988
@test Base.promote_op(+, Bool) === Int
@test isa(broadcast(+, [true]), Array{Int,1})
Expand Down
8 changes: 4 additions & 4 deletions test/nullable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,10 @@ sqr(x) = x^2
@test Nullable(2) .^ Nullable{Int}() |> isnull_oftype(Int)

# multi-arg broadcast
@test Nullable(1) .+ Nullable(1) .+ Nullable(1) .+ Nullable(1) .+ Nullable(1) .+
Nullable(1) === Nullable(6)
@test Nullable(1) .+ Nullable(1) .+ Nullable(1) .+ Nullable{Int}() .+
Nullable(1) .+ Nullable(1) |> isnull_oftype(Int)
@test (Nullable(1) .+ Nullable(1) .+ Nullable(1) .+ Nullable(1) .+ Nullable(1) .+
Nullable(1) === Nullable(6))
@test (Nullable(1) .+ Nullable(1) .+ Nullable(1) .+ Nullable{Int}() .+
Nullable(1) .+ Nullable(1) |> isnull_oftype(Int))

# these are not inferrable because there are too many arguments
us = map(Nullable, 1:20)
Expand Down

0 comments on commit 3aecb67

Please sign in to comment.