Skip to content

Commit 9fa5044

Browse files
authored
Merge pull request #60 from aplavin/master
use properties, not fields
2 parents dec3c28 + 16ba039 commit 9fa5044

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ConstructionBase"
22
uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
33
authors = ["Takafumi Arakaki", "Rafael Schouten", "Jan Weidner"]
4-
version = "1.3.0"
4+
version = "1.3.1"
55

66
[deps]
77
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/ConstructionBase.jl

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,31 @@ end
4343

4444
getproperties(o::NamedTuple) = o
4545
getproperties(o::Tuple) = o
46-
@generated function getproperties(obj)
47-
fnames = fieldnames(obj)
48-
fvals = map(fnames) do fname
49-
Expr(:call, :getproperty, :obj, QuoteNode(fname))
46+
if VERSION >= v"1.7"
47+
function getproperties(obj)
48+
fnames = propertynames(obj)
49+
NamedTuple{fnames}(getproperty.(Ref(obj), fnames))
50+
end
51+
else
52+
@generated function getproperties(obj)
53+
if which(propertynames, Tuple{obj}).sig != Tuple{typeof(propertynames), Any}
54+
# custom propertynames defined for this type
55+
return quote
56+
msg = """
57+
Different fieldnames and propertynames are only supported on Julia v1.7+.
58+
For older julia versions, consider overloading
59+
`ConstructionBase.getproperties(obj::$(typeof(obj))`.
60+
See also https://github.com/JuliaObjects/ConstructionBase.jl/pull/60.
61+
"""
62+
error(msg)
63+
end
64+
end
65+
fnames = fieldnames(obj)
66+
fvals = map(fnames) do fname
67+
:(obj.$fname)
68+
end
69+
:(NamedTuple{$fnames}(($(fvals...),)))
5070
end
51-
fvals = Expr(:tuple, fvals...)
52-
:(NamedTuple{$fnames}($fvals))
5371
end
5472

5573
################################################################################
@@ -86,9 +104,8 @@ function validate_setproperties_result(
86104
end
87105
@noinline function validate_setproperties_result(nt_new, nt_old, obj, patch)
88106
O = typeof(obj)
89-
P = typeof(patch)
90107
msg = """
91-
Failed to assign properties $(fieldnames(P)) to object with fields $(fieldnames(O)).
108+
Failed to assign properties $(propertynames(patch)) to object with properties $(propertynames(obj)).
92109
You may want to overload
93110
ConstructionBase.setproperties(obj::$O, patch::NamedTuple)
94111
ConstructionBase.getproperties(obj::$O)

test/runtests.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,30 @@ end
238238
end
239239
end
240240

241+
# example of a struct with different fields and properties
242+
struct FieldProps{NT <: NamedTuple{(:a, :b)}}
243+
components::NT
244+
end
245+
246+
Base.propertynames(obj::FieldProps) = (:a, :b)
247+
Base.getproperty(obj::FieldProps, name::Symbol) = getproperty(getfield(obj, :components), name)
248+
ConstructionBase.constructorof(::Type{<:FieldProps}) = (a, b) -> FieldProps((a=a, b=b))
249+
250+
@testset "use properties, not fields" begin
251+
x = FieldProps((a=1, b=:b))
252+
if VERSION >= v"1.7"
253+
@test getproperties(x) == (a=1, b=:b)
254+
@test setproperties(x, a="aaa") == FieldProps((a="aaa", b=:b))
255+
VERSION >= v"1.8-dev" ?
256+
(@test_throws "Failed to assign properties (:c,) to object with properties (:a, :b)" setproperties(x, c=0)) :
257+
(@test_throws ArgumentError setproperties(x, c=0))
258+
else
259+
@test_throws ErrorException getproperties(x)
260+
@test_throws ErrorException setproperties(x, a="aaa")
261+
@test_throws ErrorException setproperties(x, c=0)
262+
end
263+
end
264+
241265
function funny_numbers(::Type{Tuple}, n)::Tuple
242266
types = [
243267
Int128, Int16, Int32, Int64, Int8,

0 commit comments

Comments
 (0)