Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support dots for unary operators #20249

Merged
merged 3 commits into from
Feb 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -655,7 +655,7 @@ julia> 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.

More specifically, `a .^ b` is parsed as the ["dot" call](@ref man-vectorized)
`(^).(a,b)`, which performs a [broadcast](@ref Broadcasting) operation:
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 @@ -302,6 +302,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) .+
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this change related?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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