Skip to content

Make use of ConstructionBase #105

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.jl.mem
docs/build/
tmp*
Manifest.toml
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
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.
Expand Down Expand Up @@ -41,10 +39,14 @@ c = BB.c
```
"""
module Parameters
import ConstructionBase
using ConstructionBase: setproperties

import Base: @__doc__
import OrderedCollections: OrderedDict

export @with_kw, @with_kw_noshow, type2dict, reconstruct, @unpack, @pack!, @pack
export setproperties

## Parser helpers
#################
Expand Down Expand Up @@ -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

Expand All @@ -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)


Expand Down
19 changes: 15 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,6 +36,8 @@ end
# @test "A field Default: sdaf\n" == Markdown.plain(@doc MT1.c)
@test "Field r Default: 4\n" == Markdown.plain(REPL.fielddoc(MT1, :r))
@test "A field Default: sdaf\n" == Markdown.plain(REPL.fielddoc(MT1, :c))
@test setproperties(MT1(), r=12).r === 12
@test setproperties(MT1(), r=12, c=nothing).c === nothing

abstract type AMT1_2 end
"Test documentation with type-parameter"
Expand Down Expand Up @@ -75,7 +77,8 @@ const TMT1_3 = MT1_3{Int} # Julia bug https://github.com/JuliaLang/julia/issues/
end
MT2(r=4, a=5., c=6)
MT2(r=4, a=5, c="asdf")
MT2(4, "dsaf", 5)
obj = MT2(4, "dsaf", 5)
@test setproperties(obj, (r=42, c=:c)).r === 42
@test_throws ErrorException MT2(r=4)
@test_throws ErrorException MT2()

Expand Down Expand Up @@ -114,6 +117,12 @@ MT3_2(a=5)
MT3_2(4,5)
@test_throws ErrorException MT3_2(r=4)
@test_throws ErrorException MT3_2()
o = MT3_2(r=4, a=5.0)
o2 = setproperties(o, r=10, a=20)
@test o2.r === 10
@test o2.a === 20.0
@test o.r === 4
@test o.a === 5.0

# with type-parameters
@with_kw struct MT4{R,I}
Expand All @@ -130,6 +139,8 @@ mt4=MT4(5.4, 4) # outer positional
@test_throws ErrorException MT4{Float32, Int}()
@test_throws InexactError MT4{Float32,Int}(a=5.5)
@test_throws InexactError MT4{Float32,Int}(5.5, 5.5)
@test setproperties(MT4(a=1), r=12.0).r === 12.0
@test setproperties(MT4(a=1), r=12, a=:hello).a === :hello

# with type-parameters 2
abstract type AMT{R<:Real} end
Expand Down