Skip to content

Commit

Permalink
Fix delegation for Dict functions returning the underlying Dict
Browse files Browse the repository at this point in the history
* When called on an Associative container, delete!, empty!, sizehint!
  and setindex! all return the container
* The `@delegate` macro is not aware of this, and instead returned
  the wrapped object.
* Fixed by creating a second macro, `@delegate_return_parent`,
  which works like `@delegate`, but returns the parent container.
  • Loading branch information
kmsquire committed Jan 16, 2017
1 parent 0d99898 commit 1373a7b
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 11 deletions.
26 changes: 16 additions & 10 deletions src/default_dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ DefaultDictBase{F,D<:Associative}(default::F, d::D) = (K=keytype(d); V=valtype(d
# Functions

# most functions are simply delegated to the wrapped dictionary
@delegate DefaultDictBase.d [ sizehint!, empty!, setindex!, get, haskey,
getkey, pop!, delete!, start, done, next,
isempty, length ]
@delegate DefaultDictBase.d [ get, haskey, getkey, pop!,
start, done, next, isempty, length ]

# NOTE: push! is not included below, because the fallback version just
# calls setindex!
@delegate_return_parent DefaultDictBase.d [ delete!, empty!, setindex!, sizehint! ]

similar{K,V,F}(d::DefaultDictBase{K,V,F}) = DefaultDictBase{K,V,F}(d.default)
in{T<:DefaultDictBase}(key, v::Base.KeyIterator{T}) = key in keys(v.dict.d)
Expand Down Expand Up @@ -94,11 +97,14 @@ for (DefaultDict,O) in [(:DefaultDict, :Unordered), (:DefaultOrderedDict, :Order
## Functions

# Most functions are simply delegated to the wrapped DefaultDictBase object
@delegate $DefaultDict.d [ sizehint!, empty!, setindex!,
getindex, get, get!, haskey,
getkey, pop!, delete!, start, next,
@delegate $DefaultDict.d [ getindex, get, get!, haskey,
getkey, pop!, start, next,
done, isempty, length ]

# NOTE: push! is not included below, because the fallback version just
# calls setindex!
@delegate_return_parent $DefaultDict.d [ delete!, empty!, setindex!, sizehint! ]

similar{K,V,F}(d::$DefaultDict{K,V,F}) = $DefaultDict{K,V,F}(d.d.default)
in{T<:$DefaultDict}(key, v::Base.KeyIterator{T}) = key in keys(v.dict.d.d)
end
Expand Down Expand Up @@ -137,10 +143,10 @@ end

## Most functions are simply delegated to the wrapped DefaultDictBase object

# @delegate DefaultSortedDict.d [ sizehint!, empty!, setindex!,
# getindex, get, get!, haskey,
# getkey, pop!, delete!, start, next,
# done, isempty, length]
# @delegate DefaultSortedDict.d [ getindex, get, get!, haskey,
# getkey, pop!, start, next,
# done, isempty, length]
# @delegate_return_parent DefaultSortedDict.d [ delete!, empty!, setindex!, sizehint! ]

# similar{K,V,F}(d::DefaultSortedDict{K,V,F}) = DefaultSortedDict{K,V,F}(d.d.default)
# in{T<:DefaultSortedDict}(key, v::Base.KeyIterator{T}) = key in keys(v.dict.d.d)
18 changes: 17 additions & 1 deletion src/delegate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ macro delegate(source, targets)
fieldname = source.args[2].args[1]
funcnames = targets.args
n = length(funcnames)
fdefs = Array(Any, n)
fdefs = Vector{Any}(n)
for i in 1:n
funcname = esc(funcnames[i])
fdefs[i] = quote
Expand All @@ -14,3 +14,19 @@ macro delegate(source, targets)
end
return Expr(:block, fdefs...)
end

macro delegate_return_parent(source, targets)
typename = esc(source.args[1])
fieldname = source.args[2].args[1]
funcnames = targets.args
n = length(funcnames)
fdefs = Vector{Any}(n)
for i in 1:n
funcname = esc(funcnames[i])
fdefs[i] = quote
($funcname)(a::($typename), args...) =
(($funcname)(a.$fieldname, args...); a)
end
end
return Expr(:block, fdefs...)
end

0 comments on commit 1373a7b

Please sign in to comment.