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

Add getindex methods for NamedTuple #38878

Merged
merged 6 commits into from
Jan 13, 2021
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 @@ -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

Expand Down
14 changes: 11 additions & 3 deletions base/namedtuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,6 +30,9 @@ julia> x.a
julia> x[:a]
1

julia> x[(:a,)]
(a = 1,)

julia> keys(x)
(:a, :b)

Expand Down Expand Up @@ -76,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

Expand Down Expand Up @@ -116,6 +122,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, idxs::Tuple{Vararg{Symbol}}) = NamedTuple{idxs}(t)
Copy link
Member

Choose a reason for hiding this comment

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

Sorry if this has been discussed elsewhere, but why the @inline? Seems to not match the other methods around and should be simple enough inline by itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's how Jeff wrote it in the attached issue (#38834) - TBH I still don't totally understand what @inline does 🤷 . Happy to leave or remove

@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
Expand Down
11 changes: 11 additions & 0 deletions test/namedtuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,20 @@
@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,)
@test (x=4, y=5, z=6)[[:x, :y]] == (x=4, y=5)
@test (x=4, y=5, z=6)[[:x]] == (x=4,)
kescobo marked this conversation as resolved.
Show resolved Hide resolved
@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]