Skip to content

Commit b013403

Browse files
martinholtersstevengj
authored andcommitted
Remove compat at-dot, at-view, and at-views macros (#627)
These were added in #316 for Julia versions older than 0.6. The at-dotcompat macro is kept to avoid breakage.
1 parent 96e41ae commit b013403

File tree

3 files changed

+10
-305
lines changed

3 files changed

+10
-305
lines changed

README.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,6 @@ Currently, the `@compat` macro supports the following syntaxes:
120120

121121
## New functions, macros, and methods
122122

123-
* `@views` takes an expression and converts all slices to views ([#20164]), while
124-
`@view` ([#16564]) converts a single array reference to a view ([#20164]).
125-
126-
* `@__dot__` takes an expression and converts all assignments, function calls,
127-
and operators to their broadcasting "dot-call" equivalents ([#20321]). In Julia 0.6, this
128-
can be abbreviated `@.`, but that macro name does not parse in earlier Julia versions.
129-
For this to work in older versions of Julia (prior to 0.5) that don't have dot calls,
130-
you should instead use `@dotcompat`, which combines the `@__dot__` and `@compat` macros.
131-
132123
* [`normalize`](http://docs.julialang.org/en/latest/stdlib/linalg/?highlight=normalize#Base.normalize) and [`normalize!`](http://docs.julialang.org/en/latest/stdlib/linalg/?highlight=normalize#Base.normalize!), normalizes a vector with respect to the p-norm ([#13681])
133124

134125
* `redirect_stdout`, `redirect_stderr`, and `redirect_stdin` take an optional function as a first argument, `redirect_std*(f, stream)`, so that one may use `do` block syntax (as first available for Julia 0.6)
@@ -497,7 +488,6 @@ includes this fix. Find the minimum version from there.
497488
`Compat <version>`
498489

499490
[#13681]: https://github.com/JuliaLang/julia/issues/13681
500-
[#16564]: https://github.com/JuliaLang/julia/issues/16564
501491
[#16986]: https://github.com/JuliaLang/julia/issues/16986
502492
[#17302]: https://github.com/JuliaLang/julia/issues/17302
503493
[#17323]: https://github.com/JuliaLang/julia/issues/17323
@@ -517,8 +507,6 @@ includes this fix. Find the minimum version from there.
517507
[#19950]: https://github.com/JuliaLang/julia/issues/19950
518508
[#20005]: https://github.com/JuliaLang/julia/issues/20005
519509
[#20022]: https://github.com/JuliaLang/julia/issues/20022
520-
[#20164]: https://github.com/JuliaLang/julia/issues/20164
521-
[#20321]: https://github.com/JuliaLang/julia/issues/20321
522510
[#20407]: https://github.com/JuliaLang/julia/issues/20407
523511
[#20974]: https://github.com/JuliaLang/julia/issues/20974
524512
[#21197]: https://github.com/JuliaLang/julia/issues/21197

src/arraymacros.jl

Lines changed: 6 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,201 +1,7 @@
1-
# Julia 0.6 macros to aid in vectorization: @view, @views, @__dot__ (@.),
2-
# backported from Julia 0.6.
3-
4-
# prior to julia#20247, the replace_ref_end! macro had hygiene bugs
5-
if VERSION < v"0.6.0-dev.2406"
6-
function trailingsize(A, n)
7-
s = 1
8-
for i=n:ndims(A)
9-
s *= size(A,i)
10-
end
11-
return s
12-
end
13-
replace_ref_end!(ex) = replace_ref_end_!(ex, nothing)[1]
14-
# replace_ref_end_!(ex,withex) returns (new ex, whether withex was used)
15-
function replace_ref_end_!(ex, withex)
16-
used_withex = false
17-
if isa(ex,Symbol) && ex == :end
18-
withex === nothing && error("Invalid use of end")
19-
return withex, true
20-
elseif isa(ex,Expr)
21-
if ex.head == :ref
22-
ex.args[1], used_withex = replace_ref_end_!(ex.args[1],withex)
23-
S = isa(ex.args[1],Symbol) ? ex.args[1]::Symbol : gensym(:S) # temp var to cache ex.args[1] if needed
24-
used_S = false # whether we actually need S
25-
# new :ref, so redefine withex
26-
nargs = length(ex.args)-1
27-
if nargs == 0
28-
return ex, used_withex
29-
elseif nargs == 1
30-
# replace with endof(S)
31-
ex.args[2], used_S = replace_ref_end_!(ex.args[2],:($endof($S)))
32-
else
33-
n = 1
34-
J = endof(ex.args)
35-
for j = 2:J-1
36-
exj, used = replace_ref_end_!(ex.args[j],:($size($S,$n)))
37-
used_S |= used
38-
ex.args[j] = exj
39-
if isa(exj,Expr) && exj.head == :...
40-
# splatted object
41-
exjs = exj.args[1]
42-
n = :($n + length($exjs))
43-
elseif isa(n, Expr)
44-
# previous expression splatted
45-
n = :($n + 1)
46-
else
47-
# an integer
48-
n += 1
49-
end
50-
end
51-
ex.args[J], used = replace_ref_end_!(ex.args[J],:($trailingsize($S,$n)))
52-
used_S |= used
53-
end
54-
if used_S && S !== ex.args[1]
55-
S0 = ex.args[1]
56-
ex.args[1] = S
57-
ex = Expr(:let, ex, :($S = $S0))
58-
end
59-
else
60-
# recursive search
61-
for i = eachindex(ex.args)
62-
ex.args[i], used = replace_ref_end_!(ex.args[i],withex)
63-
used_withex |= used
64-
end
65-
end
66-
end
67-
ex, used_withex
68-
end
69-
end
70-
71-
if !isdefined(Base, Symbol("@view"))
72-
macro view(ex)
73-
if Meta.isexpr(ex, :ref)
74-
ex = replace_ref_end!(ex)
75-
if Meta.isexpr(ex, :ref)
76-
ex = Expr(:call, view, ex.args...)
77-
else # ex replaced by let ...; foo[...]; end
78-
assert(Meta.isexpr(ex, :let) && Meta.isexpr(ex.args[1], :ref))
79-
ex.args[1] = Expr(:call, view, ex.args[1].args...)
80-
end
81-
Expr(:&&, true, esc(ex))
82-
else
83-
throw(ArgumentError("Invalid use of @view macro: argument must be a reference expression A[...]."))
84-
end
85-
end
86-
export @view
87-
end
88-
89-
if !isdefined(Base, Symbol("@views"))
90-
maybeview(A, args...) = getindex(A, args...)
91-
maybeview(A::AbstractArray, args...) = view(A, args...)
92-
maybeview(A::AbstractArray, args::Number...) = getindex(A, args...)
93-
maybeview(A) = getindex(A)
94-
maybeview(A::AbstractArray) = getindex(A)
95-
96-
_views(x) = x
97-
function _views(ex::Expr)
98-
if ex.head in (:(=), :(.=))
99-
# don't use view for ref on the lhs of an assignment,
100-
# but still use views for the args of the ref:
101-
lhs = ex.args[1]
102-
Expr(ex.head, Meta.isexpr(lhs, :ref) ?
103-
Expr(:ref, map(_views, lhs.args)...) : _views(lhs),
104-
_views(ex.args[2]))
105-
elseif ex.head == :ref
106-
Expr(:call, maybeview, map(_views, ex.args)...)
107-
else
108-
h = string(ex.head)
109-
# don't use view on the lhs of an op-assignment a[i...] += ...
110-
if last(h) == '=' && Meta.isexpr(ex.args[1], :ref)
111-
lhs = ex.args[1]
112-
113-
# temp vars to avoid recomputing a and i,
114-
# which will be assigned in a let block:
115-
a = gensym(:a)
116-
i = [gensym(:i) for k = 1:length(lhs.args)-1]
117-
118-
# for splatted indices like a[i, j...], we need to
119-
# splat the corresponding temp var.
120-
I = similar(i, Any)
121-
for k = 1:length(i)
122-
if Meta.isexpr(lhs.args[k+1], :...)
123-
I[k] = Expr(:..., i[k])
124-
lhs.args[k+1] = lhs.args[k+1].args[1] # unsplat
125-
else
126-
I[k] = i[k]
127-
end
128-
end
129-
130-
Expr(:let,
131-
Expr(first(h) == '.' ? :(.=) : :(=), :($a[$(I...)]),
132-
Expr(:call, Symbol(h[1:end-1]),
133-
:($maybeview($a, $(I...))),
134-
map(_views, ex.args[2:end])...)),
135-
:($a = $(_views(lhs.args[1]))),
136-
[:($(i[k]) = $(_views(lhs.args[k+1]))) for k=1:length(i)]...)
137-
else
138-
Expr(ex.head, map(_views, ex.args)...)
139-
end
140-
end
141-
end
142-
143-
macro views(x)
144-
esc(_views(replace_ref_end!(x)))
145-
end
146-
export @views
147-
end
148-
149-
# we can't define @. because that doesn't parse in Julia < 0.6, but
150-
# we can define @__dot__, which is what @. is sugar for:
151-
if !isdefined(Base, Symbol("@__dot__"))
152-
dottable(x) = false # avoid dotting spliced objects (e.g. view calls inserted by @view)
153-
dottable(x::Symbol) = !Base.isoperator(x) || first(string(x)) != '.' || x == :.. # don't add dots to dot operators
154-
dottable(x::Expr) = x.head != :$
155-
undot(x) = x
156-
function undot(x::Expr)
157-
if x.head == :.=
158-
Expr(:(=), x.args...)
159-
elseif x.head == :block # occurs in for x=..., y=...
160-
Expr(:block, map(undot, x.args)...)
161-
else
162-
x
163-
end
164-
end
165-
__dot__(x) = x
166-
function __dot__(x::Expr)
167-
dotargs = map(__dot__, x.args)
168-
if x.head == :call && dottable(x.args[1])
169-
Expr(:., dotargs[1], Expr(:tuple, dotargs[2:end]...))
170-
elseif x.head == :$
171-
x.args[1]
172-
elseif x.head == :let # don't add dots to "let x=... assignments
173-
Expr(:let, dotargs[1], map(undot, dotargs[2:end])...)
174-
elseif x.head == :for # don't add dots to for x=... assignments
175-
Expr(:for, undot(dotargs[1]), dotargs[2])
176-
elseif (x.head == :(=) || x.head == :function || x.head == :macro) &&
177-
Meta.isexpr(x.args[1], :call) # function or macro definition
178-
Expr(x.head, x.args[1], dotargs[2])
179-
else
180-
head = string(x.head)
181-
if last(head) == '=' && first(head) != '.'
182-
Expr(Symbol('.',head), dotargs...)
183-
else
184-
Expr(x.head, dotargs...)
185-
end
186-
end
187-
end
188-
macro __dot__(x)
189-
esc(__dot__(x))
190-
end
191-
macro dotcompat(x)
192-
esc(_compat(__dot__(x)))
193-
end
194-
export @__dot__, @dotcompat
195-
else
196-
# in 0.6, use the __dot__ function from Base.Broadcast
197-
macro dotcompat(x)
198-
esc(_compat(Base.Broadcast.__dot__(x)))
199-
end
200-
export @dotcompat
1+
# TODO deprecate
2+
# this was defined for use with Julia versions prior to 0.5
3+
# (see https://github.com/JuliaLang/Compat.jl/pull/316)
4+
macro dotcompat(x)
5+
esc(_compat(Base.Broadcast.__dot__(x)))
2016
end
7+
export @dotcompat

test/runtests.jl

Lines changed: 4 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -297,106 +297,17 @@ eval(Expr(
297297
@test !isabstracttype(ConcreteFoo200061)
298298
@test !isabstracttype(StridedArray)
299299

300-
# @view and @views tests copied from Base
301-
let X = reshape(1:24,2,3,4), Y = 4:-1:1
302-
@test isa(@view(X[1:3]), SubArray)
303-
300+
# TODO remove these tests when deprecating @dotcompat
301+
let X = reshape(1:24,2,3,4)
304302
@test X[1:end] == @dotcompat (@view X[1:end]) # test compatibility of @. and @view
305-
@test X[1:end-3] == @view X[1:end-3]
306-
@test X[1:end,2,2] == @view X[1:end,2,2]
307-
@test reshape(X[1,2,1:end-2],2) == @view X[1,2,1:end-2]
308-
@test reshape(X[1,2,Y[2:end]],3) == @view X[1,2,Y[2:end]]
309-
@test reshape(X[1:end,2,Y[2:end]],2,3) == @view X[1:end,2,Y[2:end]]
310-
311-
u = (1,2:3)
312-
@test reshape(X[u...,2:end],2,3) == @view X[u...,2:end]
313-
@test reshape(X[(1,)...,(2,)...,2:end],3) == @view X[(1,)...,(2,)...,2:end]
314-
315-
# the following tests fail on 0.5 because of bugs in the 0.5 Base.@view
316-
# macro (a bugfix is scheduled to be backported from 0.6: julia#20247)
317-
if !isdefined(Base, Symbol("@view")) || VERSION v"0.6.0-dev.2406"
318-
# test macro hygiene
319-
let size=(x,y)-> error("should not happen"), Base=nothing
320-
@test X[1:end,2,2] == @view X[1:end,2,2]
321-
end
322-
323-
# test that side effects occur only once
324-
let foo = typeof(X)[X]
325-
@test X[2:end-1] == @view (push!(foo,X)[1])[2:end-1]
326-
@test foo == typeof(X)[X, X]
327-
end
328-
end
329-
330-
# test @views macro
331-
@views @compat let f!(x) = x[1:end-1] .+= x[2:end].^2
332-
x = [1,2,3,4]
333-
f!(x)
334-
@test x == [5,11,19,4]
335-
@test isa(x[1:3],SubArray)
336-
@test x[2] === 11
337-
@test Dict((1:3) => 4)[1:3] === 4
338-
x[1:2] .= 0
339-
@test x == [0,0,19,4]
340-
x[1:2] .= 5:6
341-
@test x == [5,6,19,4]
342-
f!(x[3:end])
343-
@test x == [5,6,35,4]
344-
x[Y[2:3]] .= 7:8
345-
@test x == [5,8,7,4]
303+
@views let
304+
x = [5,8,7,4]
346305
@dotcompat x[([3],)..., ()...] += 3 # @. should convert to .+=, test compatibility with @views
347306
@test x == [5,8,10,4]
348-
i = Int[]
349-
# test that lhs expressions in update operations are evaluated only once:
350-
x[push!(i,4)[1]] += 5
351-
@test x == [5,8,10,9] && i == [4]
352-
x[push!(i,3)[end]] += 2
353-
@test x == [5,8,12,9] && i == [4,3]
354307
@dotcompat x[3:end] = 0 # make sure @. works with end expressions in @views
355308
@test x == [5,8,0,0]
356309
end
357-
# same tests, but make sure we can switch the order of @compat and @views
358-
@compat @views let f!(x) = x[1:end-1] .+= x[2:end].^2
359-
x = [1,2,3,4]
360-
f!(x)
361-
@test x == [5,11,19,4]
362-
@test isa(x[1:3],SubArray)
363-
@test x[2] === 11
364-
@test Dict((1:3) => 4)[1:3] === 4
365-
x[1:2] .= 0
366-
@test x == [0,0,19,4]
367-
x[1:2] .= 5:6
368-
@test x == [5,6,19,4]
369-
f!(x[3:end])
370-
@test x == [5,6,35,4]
371-
x[Y[2:3]] .= 7:8
372-
@test x == [5,8,7,4]
373-
@dotcompat x[([3],)..., ()...] += 3 # @. should convert to .+=, test compatibility with @views
374-
@test x == [5,8,10,4]
375-
i = Int[]
376-
# test that lhs expressions in update operations are evaluated only once:
377-
x[push!(i,4)[1]] += 5
378-
@test x == [5,8,10,9] && i == [4]
379-
x[push!(i,3)[end]] += 2
380-
@test x == [5,8,12,9] && i == [4,3]
381-
@dotcompat x[3:end] = 0 # make sure @. works with end expressions in @views
382-
@test x == [5,8,0,0]
383-
end
384-
@views @test isa(X[1:3], SubArray)
385-
@test X[1:end] == @views X[1:end]
386-
@test X[1:end-3] == @views X[1:end-3]
387-
@test X[1:end,2,2] == @views X[1:end,2,2]
388-
@test reshape(X[1,2,1:end-2],2) == @views X[1,2,1:end-2]
389-
@test reshape(X[1,2,Y[2:end]],3) == @views X[1,2,Y[2:end]]
390-
@test reshape(X[1:end,2,Y[2:end]],2,3) == @views X[1:end,2,Y[2:end]]
391-
@test reshape(X[u...,2:end],2,3) == @views X[u...,2:end]
392-
@test reshape(X[(1,)...,(2,)...,2:end],3) == @views X[(1,)...,(2,)...,2:end]
393-
394-
# test macro hygiene
395-
let size=(x,y)-> error("should not happen"), Base=nothing
396-
@test X[1:end,2,2] == @views X[1:end,2,2]
397-
end
398310
end
399-
400311
# @. (@__dot__) tests, from base:
401312
let x = [4, -9, 1, -16]
402313
@test [2, 3, 4, 5] == @dotcompat(1 + sqrt($sort(abs(x))))

0 commit comments

Comments
 (0)