From f9c49873009623d0813dc8728b2072660816dec4 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Fri, 11 Dec 2020 21:48:28 -0500 Subject: [PATCH 1/6] add getindex method and tests for NamedTuple --- base/namedtuple.jl | 11 ++++++++--- test/namedtuple.jl | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/base/namedtuple.jl b/base/namedtuple.jl index fc3701f45ea4c..0935db308b469 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -9,9 +9,9 @@ tuple-like collection of values, where each entry has a unique name, represented can be modified in place after construction. Accessing the value associated with a name in a named tuple can be done using field -access syntax, e.g. `x.a`, or using [`getindex`](@ref), e.g. `x[:a]`. A tuple of the -names can be obtained using [`keys`](@ref), and a tuple of the values can be obtained -using [`values`](@ref). +access syntax, e.g. `x.a`, or using [`getindex`](@ref), e.g. `x[:a]` or `x[(:a, :b)]`. +A tuple of the names can be obtained using [`keys`](@ref), and a tuple of the values +can be obtained using [`values`](@ref). !!! note Iteration over `NamedTuple`s produces the *values* without the names. (See example @@ -30,6 +30,9 @@ julia> x.a julia> x[:a] 1 +julia> nt[(:a,)] +(a = 1,) + julia> keys(x) (:a, :b) @@ -116,6 +119,8 @@ firstindex(t::NamedTuple) = 1 lastindex(t::NamedTuple) = nfields(t) getindex(t::NamedTuple, i::Int) = getfield(t, i) getindex(t::NamedTuple, i::Symbol) = getfield(t, i) +@inline getindex(t::NamedTuple, i::Tuple{Vararg{Symbol}}) = NamedTuple{s}(nt) +#? Is this ok too ?# @inline getindex(t::NamedTuple, i::AbstractVector{Symbol}) = NamedTuple{Tuple(s)}(nt) indexed_iterate(t::NamedTuple, i::Int, state=1) = (getfield(t, i), i+1) isempty(::NamedTuple{()}) = true isempty(::NamedTuple) = false diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 5a248e1110ceb..4703d338cf104 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -21,6 +21,13 @@ @test (a=3,)[:a] == 3 @test (x=4, y=5, z=6).y == 5 @test (x=4, y=5, z=6).z == 6 +@test (x=4, y=5, z=6)[(:x, :y)] == (x=4, y=5) +@test (x=4, y=5, z=6)[(:x,)] == (x=4,) +# If the following are included, is it worth putting in 1 line with above, eg: +# @test (x=4, y=5, z=6)[(:x, :y)] == (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) +# or keep separate, eg: +# @test (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) +# @test (x=4, y=5, z=6)[[:x]] == (x=4,) @test_throws ErrorException (x=4, y=5, z=6).a @test_throws BoundsError (a=2,)[0] @test_throws BoundsError (a=2,)[2] From adb158699afd7c62723bc939ac66f0420eb05666 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 14 Dec 2020 14:53:30 -0500 Subject: [PATCH 2/6] fix stupid typos --- base/namedtuple.jl | 4 ++-- test/namedtuple.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 0935db308b469..ae72f237d6da9 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -119,8 +119,8 @@ firstindex(t::NamedTuple) = 1 lastindex(t::NamedTuple) = nfields(t) getindex(t::NamedTuple, i::Int) = getfield(t, i) getindex(t::NamedTuple, i::Symbol) = getfield(t, i) -@inline getindex(t::NamedTuple, i::Tuple{Vararg{Symbol}}) = NamedTuple{s}(nt) -#? Is this ok too ?# @inline getindex(t::NamedTuple, i::AbstractVector{Symbol}) = NamedTuple{Tuple(s)}(nt) +@inline getindex(t::NamedTuple, idxs::Tuple{Vararg{Symbol}}) = NamedTuple{idxs}(t) +@inline getindex(t::NamedTuple, idxs::AbstractVector{Symbol}) = NamedTuple{Tuple(idxs)}(t) indexed_iterate(t::NamedTuple, i::Int, state=1) = (getfield(t, i), i+1) isempty(::NamedTuple{()}) = true isempty(::NamedTuple) = false diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 4703d338cf104..ef7aa6eadf763 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -26,8 +26,8 @@ # If the following are included, is it worth putting in 1 line with above, eg: # @test (x=4, y=5, z=6)[(:x, :y)] == (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) # or keep separate, eg: -# @test (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) -# @test (x=4, y=5, z=6)[[:x]] == (x=4,) +@test (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) +@test (x=4, y=5, z=6)[[:x]] == (x=4,) @test_throws ErrorException (x=4, y=5, z=6).a @test_throws BoundsError (a=2,)[0] @test_throws BoundsError (a=2,)[2] From 6978d6817e273bd49b2cf66567f311a61bec0e6f Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 14 Dec 2020 15:44:21 -0500 Subject: [PATCH 3/6] more stupid typos --- base/namedtuple.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/namedtuple.jl b/base/namedtuple.jl index ae72f237d6da9..92a9d931f33fc 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -30,7 +30,7 @@ julia> x.a julia> x[:a] 1 -julia> nt[(:a,)] +julia> x[(:a,)] (a = 1,) julia> keys(x) From 0539fbb3dcfd8b022e8101118b5b5c268f465996 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Sun, 27 Dec 2020 13:59:59 -0500 Subject: [PATCH 4/6] test suggestions from jw3126 --- test/namedtuple.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/namedtuple.jl b/test/namedtuple.jl index ef7aa6eadf763..ccf04bdb7d8e0 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -28,9 +28,16 @@ # or keep separate, eg: @test (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) @test (x=4, y=5, z=6)[[:x]] == (x=4,) +@test (x=4, y=5, z=6)[()] == NamedTuple() +@test NamedTuple()[()] == NamedTuple() @test_throws ErrorException (x=4, y=5, z=6).a @test_throws BoundsError (a=2,)[0] @test_throws BoundsError (a=2,)[2] +@test_throws ErrorException (x=4, y=5, z=6)[(:a,)] +@test_throws ErrorException (x=4, y=5, z=6)[(:x, :a)] +@test_throws ErrorException (x=4, y=5, z=6)[[:a]] +@test_throws ErrorException (x=4, y=5, z=6)[[:x, :a]] +@test_throws ErrorException (x=4, y=5, z=6)[(:x, :x)] @test length(NamedTuple()) == 0 @test length((a=1,)) == 1 From 312faea586f37bae5e8cf3b368e61ede98866f1c Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Wed, 13 Jan 2021 10:41:36 -0500 Subject: [PATCH 5/6] remove comments from tests --- test/namedtuple.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/namedtuple.jl b/test/namedtuple.jl index ccf04bdb7d8e0..128cff5f53731 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -23,9 +23,6 @@ @test (x=4, y=5, z=6).z == 6 @test (x=4, y=5, z=6)[(:x, :y)] == (x=4, y=5) @test (x=4, y=5, z=6)[(:x,)] == (x=4,) -# If the following are included, is it worth putting in 1 line with above, eg: -# @test (x=4, y=5, z=6)[(:x, :y)] == (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) -# or keep separate, eg: @test (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5) @test (x=4, y=5, z=6)[[:x]] == (x=4,) @test (x=4, y=5, z=6)[()] == NamedTuple() From 468cfe8d6c6a852c8355811dcf37fe3c9c4f0033 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Wed, 13 Jan 2021 12:51:50 -0500 Subject: [PATCH 6/6] add compat notice and NEWS --- NEWS.md | 1 + base/namedtuple.jl | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index e4c88c5b25177..61f3eb4fb8867 100644 --- a/NEWS.md +++ b/NEWS.md @@ -45,6 +45,7 @@ Standard library changes * `iseven` and `isodd` functions now support non-`Integer` numeric types ([#38976]). * `escape_string` can now receive a collection of characters in the keyword `keep` that are to be kept as they are. ([#38597]). +* `getindex` can now be used on `NamedTuple`s with multiple values ([#38878]) #### Package Manager diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 92a9d931f33fc..ac38f0b1ec2d4 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -79,6 +79,9 @@ julia> (; t.x) !!! compat "Julia 1.5" Implicit names from identifiers and dot expressions are available as of Julia 1.5. + +!!! compat "Julia 1.7" + Use of `getindex` methods with multiple `Symbol`s is available as of Julia 1.7. """ Core.NamedTuple