Skip to content

Commit 5a3c408

Browse files
author
Andy Ferris
committed
Added `empty
* `empty` returns an `Associative` with no keys, replacing `similar`. * `similar` now ensures the `Associative`'s keys are initialized, and matches more closely the behavior of `similar(::AbstractArray)`.
1 parent 695fedb commit 5a3c408

File tree

14 files changed

+168
-29
lines changed

14 files changed

+168
-29
lines changed

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,13 @@ Deprecated or removed
12491249
12501250
* `EnvHash` has been renamed to `EnvDict` ([#24167]).
12511251
1252+
* Introduced the `empty` function, the functional pair to `empty!` which returns a new,
1253+
empty container ([#24390]).
1254+
1255+
* `similar(::Associative)` has been deprecated in favor of `empty(::Associative)`, and
1256+
`similar(::Associative, ::Pair{K, V})` has been deprecated in favour of
1257+
`empty(::Associative, K, V)` ([#24390]).
1258+
12521259
Command-line option changes
12531260
---------------------------
12541261

base/abstractarray.jl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,8 +563,26 @@ of the columns of `A`.
563563
would create an array of `Int`, initialized to zero, matching the
564564
indices of `A`.
565565
"""
566-
similar(f, shape::Tuple) = f(to_shape(shape))
567-
similar(f, dims::DimOrInd...) = similar(f, dims)
566+
similar(f, shape::Tuple) = f(to_shape(shape)) # doesn't share well with Associative
567+
similar(f, dims::DimOrInd...) = similar(f, dims) # doesn't share well with Associative
568+
569+
"""
570+
empty(v::AbstractVector, [eltype])
571+
572+
Create an empty vector similar to `v`, optionally changing the `eltype`.
573+
574+
# Examples
575+
576+
```jldoctest
577+
julia> empty([1.0, 2.0, 3.0])
578+
0-element Array{Float64,1}
579+
580+
julia> empty([1.0, 2.0, 3.0], String)
581+
0-element Array{String,1}
582+
```
583+
"""
584+
empty(a::AbstractVector) = empty(a, eltype(a))
585+
empty(a::AbstractVector, ::Type{T}) where {T} = Vector{T}()
568586

569587
## from general iterable to any array
570588

base/associative.jl

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,42 @@ This includes arrays, where the keys are the array indices.
136136
"""
137137
pairs(collection) = Generator(=>, keys(collection), values(collection))
138138

139+
"""
140+
similar(a::Associative, [value_type=valtype(a)], [inds=keys(a)])
141+
142+
Create an `Associative` container with unitialized values of `value_type` and indices
143+
`inds`. The second and third arguments are optional and default to the input's `valtype` and
144+
`keys`, respectively.
145+
146+
Custom `Associative` subtypes may choose which specific associative type is best suited to
147+
return for the given value type and indices, by specializing on the three-argument
148+
signature. The default is to return a `Dict`.
149+
"""
150+
# v1.0: similar(a::Associative) = similar(a, valtype(a), keys(a))
151+
similar(a::Associative, ::Type{T}) where {T} = similar(a, T, keys(a))
152+
similar(a::Associative, inds) = similar(a, valtype(a), inds)
153+
154+
# disambiguation
155+
similar(a::Associative, t::Tuple) = similar(a, valtype(a), t)
156+
similar(a::Associative, d::DimOrInd) = similar(a, valtype(a), d)
157+
158+
"""
159+
empty(a::Associative, [index_type=keytype(a)], [value_type=valtype(a)])
160+
161+
Create an empty `Associative` container which can accept indices of type `index_type` and
162+
values of type `value_type`. The second and third arguments are optional and default to the
163+
input's `keytype` and `valtype`, respectively. (If only one of the two types is specified,
164+
it is assumed to be the `value_type`, and the `index_type` we default to `keytype(a)`).
165+
166+
Custom `Associative` subtypes may choose which specific associative type is best suited to
167+
return for the given index and value types, by specializing on the three-argument signature.
168+
The default is to return an empty `Dict`.
169+
"""
170+
empty(a::Associative) = empty(a, keytype(a), valtype(a))
171+
empty(a::Associative, ::Type{V}) where {V} = empty(a, keytype(a), V) # Note: this is the form which makes sense for `Vector`.
172+
139173
function copy(a::Associative)
140-
b = similar(a)
174+
b = empty(a)
141175
for (k,v) in a
142176
b[k] = v
143177
end
@@ -403,7 +437,7 @@ Dict{Int64,String} with 1 entry:
403437
"""
404438
function filter(f, d::Associative)
405439
# don't just do filter!(f, copy(d)): avoid making a whole copy of d
406-
df = similar(d)
440+
df = empty(d)
407441
try
408442
for (k, v) in d
409443
if f(k => v)
@@ -512,7 +546,7 @@ mutable struct ObjectIdDict <: Associative{Any,Any}
512546
ObjectIdDict(o::ObjectIdDict) = new(copy(o.ht))
513547
end
514548

515-
similar(d::ObjectIdDict) = ObjectIdDict()
549+
empty(d::ObjectIdDict, ::Type{Any}, ::Type{Any}) = ObjectIdDict()
516550

517551
function rehash!(t::ObjectIdDict, newsz = length(t.ht))
518552
t.ht = ccall(:jl_idtable_rehash, Any, (Any, Csize_t), t.ht, newsz)

base/deepcopy.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ function deepcopy_internal(x::Dict, stackdict::ObjectIdDict)
105105
return (stackdict[x] = copy(x))
106106
end
107107

108-
dest = similar(x)
108+
dest = empty(x)
109109
stackdict[x] = dest
110110
for (k, v) in x
111111
dest[deepcopy_internal(k, stackdict)] = deepcopy_internal(v, stackdict)

base/deprecated.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,6 +2093,10 @@ end
20932093
@deprecate chol!(x::Number, uplo) chol(x) false
20942094
end
20952095

2096+
# issue #24019
2097+
@deprecate similar(a::Associative) empty(a)
2098+
@deprecate similar(a::Associative, ::Type{Pair{K,V}}) where {K, V} empty(a, K, V)
2099+
20962100
# END 0.7 deprecations
20972101

20982102
# BEGIN 1.0 deprecations

base/dict.jl

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ mutable struct Dict{K,V} <: Associative{K,V}
111111
new(copy(d.slots), copy(d.keys), copy(d.vals), 0, d.count, d.age, d.idxfloor,
112112
d.maxprobe)
113113
end
114+
function Dict{K, V}(slots, keys, ndel, count, age, idxfloor, maxprobe) where {K, V}
115+
new(slots, keys, Vector{V}(length(keys)), ndel, count, age, idxfloor, maxprobe)
116+
end
114117
end
115118
function Dict{K,V}(kv) where V where K
116119
h = Dict{K,V}()
@@ -170,7 +173,7 @@ end
170173
# this is a special case due to (1) allowing both Pairs and Tuples as elements,
171174
# and (2) Pair being invariant. a bit annoying.
172175
function grow_to!(dest::Associative, itr)
173-
out = grow_to!(similar(dest, Pair{Union{},Union{}}), itr, start(itr))
176+
out = grow_to!(empty(dest, Union{}, Union{}), itr, start(itr))
174177
return isempty(out) ? dest : out
175178
end
176179

@@ -180,7 +183,7 @@ function grow_to!(dest::Associative{K,V}, itr, st) where V where K
180183
if isa(k,K) && isa(v,V)
181184
dest[k] = v
182185
else
183-
new = similar(dest, Pair{typejoin(K,typeof(k)), typejoin(V,typeof(v))})
186+
new = empty(dest, typejoin(K,typeof(k)), typejoin(V,typeof(v)))
184187
copy!(new, dest)
185188
new[k] = v
186189
return grow_to!(new, itr, st)
@@ -189,8 +192,23 @@ function grow_to!(dest::Associative{K,V}, itr, st) where V where K
189192
return dest
190193
end
191194

192-
similar(d::Dict{K,V}) where {K,V} = Dict{K,V}()
193-
similar(d::Dict, ::Type{Pair{K,V}}) where {K,V} = Dict{K,V}()
195+
function similar(a::Associative, ::Type{V}, inds) where {V}
196+
K = eltype(inds)
197+
tmp = Dict{K, Void}()
198+
for i in inds
199+
tmp[i] = nothing
200+
end
201+
return Dict{K, V}(tmp.slots, tmp.keys, tmp.ndel, tmp.count, tmp.age,
202+
tmp.idxfloor, tmp.maxprobe)
203+
end
204+
205+
# Fast copy of hashed indices from a `Dict`
206+
function similar(a::Associative, ::Type{V}, inds::KeyIterator{<:Dict{K}}) where {K, V}
207+
Dict{K, V}(copy(inds.dict.slots), copy(inds.dict.keys), inds.dict.ndel, inds.dict.count,
208+
inds.dict.age, inds.dict.idxfloor, inds.dict.maxprobe)
209+
end
210+
211+
empty(a::Associative, ::Type{K}, ::Type{V}) where {K, V} = Dict{K, V}()
194212

195213
# conversion between Dict types
196214
function convert(::Type{Dict{K,V}},d::Associative) where V where K
@@ -813,12 +831,7 @@ next(::ImmutableDict{K,V}, t) where {K,V} = (Pair{K,V}(t.key, t.value), t.parent
813831
done(::ImmutableDict, t) = !isdefined(t, :parent)
814832
length(t::ImmutableDict) = count(x->true, t)
815833
isempty(t::ImmutableDict) = done(t, start(t))
816-
function similar(t::ImmutableDict)
817-
while isdefined(t, :parent)
818-
t = t.parent
819-
end
820-
return t
821-
end
834+
empty(::ImmutableDict, ::Type{K}, ::Type{V}) where {K, V} = ImmutableDict{K,V}()
822835

823-
_similar_for(c::Dict, ::Type{P}, itr, isz) where {P<:Pair} = similar(c, P)
836+
_similar_for(c::Dict, ::Type{Pair{K,V}}, itr, isz) where {K, V} = empty(c, K, V)
824837
_similar_for(c::Associative, T, itr, isz) = throw(ArgumentError("for Associatives, similar requires an element type of Pair;\n if calling map, consider a comprehension instead"))

base/env.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ variables.
7373
"""
7474
const ENV = EnvDict()
7575

76-
similar(::EnvDict) = Dict{String,String}()
77-
7876
getindex(::EnvDict, k::AbstractString) = access_env(k->throw(KeyError(k)), k)
7977
get(::EnvDict, k::AbstractString, def) = access_env(k->def, k)
8078
get(f::Callable, ::EnvDict, k::AbstractString) = access_env(k->f(), k)

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ export
652652
deleteat!,
653653
eltype,
654654
empty!,
655+
empty,
655656
endof,
656657
filter!,
657658
filter,

base/pkg/query.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ end
4242

4343
# Specialized copy for the avail argument below because the deepcopy is slow
4444
function availcopy(avail)
45-
new_avail = similar(avail)
45+
new_avail = empty(avail)
4646
for (pkg, vers_avail) in avail
47-
new_vers_avail = similar(vers_avail)
47+
new_vers_avail = empty(vers_avail)
4848
for (version, pkg_avail) in vers_avail
4949
new_vers_avail[version] = copy(pkg_avail)
5050
end

base/tuple.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,10 @@ any(x::Tuple{}) = false
328328
any(x::Tuple{Bool}) = x[1]
329329
any(x::Tuple{Bool, Bool}) = x[1]|x[2]
330330
any(x::Tuple{Bool, Bool, Bool}) = x[1]|x[2]|x[3]
331+
332+
"""
333+
empty(x::Tuple)
334+
335+
Returns an empty tuple, `()`.
336+
"""
337+
empty(x::Tuple) = ()

0 commit comments

Comments
 (0)