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

Make use of ConstructionBase #105

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
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
Next Next commit
Make use of ConstructionBase
jw3126 committed Oct 1, 2019

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 71405e18ca41bb7ac1d3c7d026a0cc066fa42f0c
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ author = ["Mauro Werder <[email protected]>"]
version = "0.12.0"

[deps]
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"

[compat]
Copy link
Contributor

Choose a reason for hiding this comment

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

How about adding ConstructionBase = "0.1, 1.0"? (I think CompatHelper can figure out 1.0 but I'm not sure if it adds 0.1)

48 changes: 25 additions & 23 deletions src/Parameters.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
__precompile__()

"""
This is a package I use to handle numerical-model parameters,
thus the name. However, it should be useful otherwise too.
@@ -41,6 +39,10 @@ c = BB.c
```
"""
module Parameters
import ConstructionBase
using ConstructionBase: setproperties
export setproperties

import Base: @__doc__
import OrderedCollections: OrderedDict

@@ -199,11 +201,7 @@ end
"""
Make a new instance of a type with the same values as the input type
except for the fields given in the AbstractDict second argument or as
keywords. Works for types, Dicts, and NamedTuples.

Note: this is not very performant. Check Setfield.jl for a faster &
nicer implementation.

keywords. Works for types, Dicts, and NamedTuples.
```jldoctest
julia> using Parameters

@@ -218,25 +216,29 @@ A(3, 4)
julia> b = reconstruct(a, b=99)
A(3, 99)
```
See also [`setproperties`](@ref).

# Overloading
#
If you want to overload `reconstruct` consider overloading `setproperties` instead.
More precisely if you have a dict like type `MyDict <: AbstractDict`, it makes
sense to overload `reconstruct(o::MyDict, di)`. If you have a record like type,
you should probably overload `setproperties(o, patch::NamedTuple)` instead.

Formulated differently, if the goal of the reconstruct call is to update:
* the result of `getindex`, overload `reconstruct`
* the result of `getproperty` overload `setproperties` instead.
"""
function reconstruct(pp::T, di) where T
di = !isa(di, AbstractDict) ? Dict(di) : copy(di)
if pp isa AbstractDict
for (k,v) in di
!haskey(pp, k) && error("Field $k not in type $T")
pp[k] = v
end
return pp
else
ns = fieldnames(T)
args = []
for (i,n) in enumerate(ns)
push!(args, pop!(di, n, getfield(pp, n)))
end
length(di)!=0 && error("Fields $(keys(di)) not in type $T")
return pp isa NamedTuple ? T(Tuple(args)) : T(args...)
function reconstruct(pp::AbstractDict, di)
# di = !isa(di, AbstractDict) ? Dict(di) : copy(di)
for (k,v) in di
!haskey(pp, k) && throw(KeyError(k))
pp[k] = v
end
return pp
end
reconstruct(obj, patch::NamedTuple) = setproperties(obj, patch)
reconstruct(obj, patch) = reconstruct(obj, (;patch...))
reconstruct(pp; kws...) = reconstruct(pp, kws)


6 changes: 3 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -4,19 +4,19 @@ using Parameters, Test, Markdown, REPL
a8679 = @eval (a=1, b=2)
ra8679 = @eval (a=1, b=44)
@test ra8679 == reconstruct(a8679, b=44)
@test_throws ErrorException reconstruct(a8679, c=44)
@test_throws ArgumentError reconstruct(a8679, c=44)

a8679 = Dict(:a=>1, :b=>2)
@test Dict(:a=>1, :b=>44) == reconstruct(a8679, b=44)
@test_throws ErrorException reconstruct(a8679, c=44)
@test_throws KeyError reconstruct(a8679, c=44)

struct A8679
a
b
end
a8679 = A8679(1, 2)
@test A8679(1, 44) == reconstruct(a8679, b=44)
@test_throws ErrorException reconstruct(a8679, c=44)
@test_throws ArgumentError reconstruct(a8679, c=44)

##########
# @with_kw