From afe134e073c58075923f0fea3c67cff822653a93 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 26 Jan 2018 16:13:53 -0500 Subject: [PATCH 1/3] Simplify A[1, end] lowering with lastindex(A, n) This implements a new method of `lastindex` to specify a given dimension, and then uses that new method in the lowering of `end` within multi-dimensional indices. Previously, this would have lowered directly to `last(axes(A, d))` for `end` in position `d`. Given that `axes` (and multidimensional indexing generally) are array-centric concepts, I have only implemented this for `::AbstractArray`, with a deprecation for all other types suggesting implemention if sensible. I have similarly defined `firstindex(A, d)` - it will be available for its syntax transformation in the future. --- base/abstractarray.jl | 2 ++ base/deprecated.jl | 6 ++++++ src/julia-syntax.scm | 6 +++--- test/abstractarray.jl | 11 ++++++++++- test/offsetarray.jl | 3 +++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 9eb87fee2647c..27b85da2ba564 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -176,6 +176,7 @@ julia> lastindex([1,2,4]) ``` """ lastindex(a::AbstractArray) = (@_inline_meta; last(linearindices(a))) +lastindex(a::AbstractArray, n) = (@_inline_meta; last(axes(a, n))) """ firstindex(collection) -> Integer @@ -189,6 +190,7 @@ julia> firstindex([1,2,4]) ``` """ firstindex(a::AbstractArray) = (@_inline_meta; first(linearindices(a))) +firstindex(a::AbstractArray, n) = (@_inline_meta; first(axes(a, n))) first(a::AbstractArray) = a[first(eachindex(a))] diff --git a/base/deprecated.jl b/base/deprecated.jl index 0b108ede155e9..8dd7d4cc4c395 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1392,6 +1392,12 @@ function firstindex(a) 1 end +# PR 25763 +function lastindex(a, n) + depwarn("if appropriate you should implement `lastindex(a, n)` for type $(typeof(a))`, which might just return `last(axes(a, n))`", :lastindex) + last(axes(a, n)) +end + @deprecate Timer(timeout, repeat) Timer(timeout, interval = repeat) @deprecate Timer(callback, delay, repeat) Time(callback, delay, interval = repeat) @deprecate names(m, all) names(m, all = all) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index aef2a8485da17..180e8c70f5807 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -90,16 +90,16 @@ ;; the array `a` in the `n`th index. ;; `tuples` are a list of the splatted arguments that precede index `n` ;; `last` = is this last index? -;; returns a call to lastindex(a) or last(axes(a,n)) +;; returns a call to lastindex(a) or lastindex(a,n)) (define (end-val a n tuples last) (if (null? tuples) (if (and last (= n 1)) `(call (top lastindex) ,a) - `(call (top last) (call (top axes) ,a ,n))) + `(call (top lastindex) ,a ,n)) (let ((dimno `(call (top +) ,(- n (length tuples)) ,.(map (lambda (t) `(call (top length) ,t)) tuples)))) - `(call (top last) (call (top axes) ,a ,dimno))))) + `(call (top lastindex) ,a ,dimno)))) ;; replace `end` for the closest ref expression, so doesn't go inside nested refs (define (replace-end ex a n tuples last) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 19d84867a1bc8..f66b4c94d44c7 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -453,7 +453,16 @@ function test_primitives(::Type{T}, shape, ::Type{TestAbstractArray}) where T B = T(A) # last(a) - @test last(B) == B[length(B)] + @test last(B) == B[lastindex(B)] == B[end] == A[end] + @test lastindex(B) == lastindex(A) == last(linearindices(B)) + @test lastindex(B, 1) == lastindex(A, 1) == last(axes(B, 1)) + @test lastindex(B, 2) == lastindex(A, 2) == last(axes(B, 2)) + + # first(a) + @test first(B) == B[firstindex(B)] == B[1] == A[1] # TODO: use B[begin] once parser transforms it + @test firstindex(B) == firstindex(A) == first(linearindices(B)) + @test firstindex(B, 1) == firstindex(A, 1) == first(axes(B, 1)) + @test firstindex(B, 2) == firstindex(A, 2) == first(axes(B, 2)) # isassigned(a::AbstractArray, i::Int...) j = rand(1:length(B)) diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 631bfee14c5aa..de21878a1cf72 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -328,6 +328,9 @@ cv = copy(v) @test reverse!(cv) == rv A = OffsetArray(rand(4,4), (-3,5)) +@test lastindex(A) == 16 +@test lastindex(A, 1) == 1 +@test lastindex(A, 2) == 9 @test A ≈ A @test axes(A') === (6:9, -2:1) @test parent(copy(A')) == copy(parent(A)') From 7f3e69effa20e26d12d89f1cf9a312f5a09a854a Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 26 Jan 2018 16:21:32 -0500 Subject: [PATCH 2/3] Update NEWS.md --- NEWS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 4bc1c5c37c8ec..9e9670668eaca 100644 --- a/NEWS.md +++ b/NEWS.md @@ -993,7 +993,9 @@ Deprecated or removed * `scale!` has been deprecated in favor of `mul!`, `mul1!`, and `mul2!` ([#25701]). - * `endof(a)` has been renamed to `lastindex(a)` ([#23554]). + * `endof(a)` has been renamed to `lastindex(a)`, and the `end` keyword in indexing expressions now + lowers to either `lastindex(a)` (in the case with only one index) or `lastindex(a, d)` (in cases + where there is more than one index and `end` appears at dimension `d`) ([#23554], [#25763]). * `DateTime()`, `Date()`, and `Time()` have been deprecated, instead use `DateTime(1)`, `Date(1)` and `Time(0)` respectively ([#23724]). From 19e6c45e0bdda6d249979e026a59fef0fbfe9ad3 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 26 Jan 2018 15:36:34 -0600 Subject: [PATCH 3/3] Remove unpaired `)` from comment --- src/julia-syntax.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 180e8c70f5807..25740675aa348 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -90,7 +90,7 @@ ;; the array `a` in the `n`th index. ;; `tuples` are a list of the splatted arguments that precede index `n` ;; `last` = is this last index? -;; returns a call to lastindex(a) or lastindex(a,n)) +;; returns a call to lastindex(a) or lastindex(a,n) (define (end-val a n tuples last) (if (null? tuples) (if (and last (= n 1))