Skip to content

Commit e1ed31e

Browse files
committed
added inheritance
1 parent b6b95bd commit e1ed31e

4 files changed

Lines changed: 99 additions & 81 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DynamicObjects"
22
uuid = "23d02862-63fe-4c6e-8fdb-1d52cbbd39d5"
33
authors = ["Nikolas Siccha <nikolassiccha@gmail.com> and contributors"]
4-
version = "0.1.2"
4+
version = "0.1.3"
55

66
[deps]
77
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Implements a dynamic object type which can be redefined with convenient/confusing `.`-syntax and caching.
44

5+
See [https://nsiccha.github.io/examples/DynamicObjects.jl/](https://nsiccha.github.io/examples/DynamicObjects.jl/) for examples.
6+
57
```julia
68
using DynamicObjects
79

@@ -21,5 +23,4 @@ A Rectangle(height = 10, width = 20) has an area of 200.
2123

2224
## To add/fix:
2325

24-
* Inheritance (e.g. `@dynamic_object Rectangle <: Polygon height width`)
2526
* Defining a single argument type without a type on that argument (e.g. `@dynamic_object Circle radius`)

examples/geometry.qmd

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/DynamicObjects.jl

Lines changed: 96 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
module DynamicObjects
2-
export DynamicObject, @dynamic_object#, update, cached,
2+
export AbstractDynamicObject, DynamicObject, @dynamic_object, @dynamic_type#, update, cached,
33
import Serialization
44

5-
"""
6-
DynamicObject{T}
75

8-
A `DynamicObject` is a thin named wrapper around a generic NamedTuple which enables function overloading.
9-
The type is inefficient computationally, but can enable more efficient prototyping/development.
10-
"""
11-
struct DynamicObject{T}
12-
nt::NamedTuple
13-
DynamicObject{T}(nt::NamedTuple) where T = new(nt)
14-
end
156
esc_arg(arg::Symbol) = esc(arg)
167
function esc_arg(arg::Expr)
178
if arg.head == :(=)
@@ -43,75 +34,128 @@ This dynamic type can be used in function definitions as
4334
area(what::Rectangle) = what.height * what.width
4435
```
4536
"""
37+
get_sname(name::Symbol) = QuoteNode(name)
38+
get_sname(name::Expr) = QuoteNode(name.args[1])
39+
ename_and_ebase(name::Symbol, default) = esc(name), esc(default)
40+
ename_and_ebase(name::Expr, default) = esc.(name.args)
4641
macro dynamic_object(name, args...)
47-
sname = QuoteNode(name)
48-
ename = esc(name)
42+
sname = get_sname(name)
43+
ename, ebase = ename_and_ebase(name, :DynamicObject)
44+
# ename = esc(name)
4945
eargs = esc_arg.(args)
5046
kwargs = esc(:kwargs)
5147
argnames = get_arg_symbol.(args)
5248
aargs = [esc(:($(arg)=$(arg))) for arg in argnames]
5349
quote
54-
Base.@__doc__ $ename = DynamicObject{$sname}
55-
$DynamicObject{$sname}($(eargs...); $kwargs...) = DynamicObject{$sname}((
50+
Base.@__doc__ $ename = $ebase{$sname}
51+
$ebase{$sname}($(eargs...); $kwargs...) = $ebase{$sname}((
5652
$(aargs...), $kwargs...
5753
))
5854
end
5955
end
60-
Base.propertynames(value::DynamicObject) = propertynames(value.nt)
61-
function Base.getproperty(value::DynamicObject, name::Symbol)
62-
if name == :nt
63-
getfield(value, name)
64-
else
65-
if hasproperty(value.nt, name)
66-
getproperty(value.nt, name)
67-
else
68-
getfield(Main, name)(value)
56+
57+
abstract type AbstractDynamicObject end
58+
59+
macro dynamic_type(name)
60+
ename, ebase = ename_and_ebase(name, :AbstractDynamicObject)
61+
NT = esc(:NamedTuple)
62+
Base = esc(:Base)
63+
quote
64+
Base.@__doc__ struct $ename{T} <: $ebase
65+
nt::$NT
66+
# $ename{T}(nt::$NT) where T = new(nt)
67+
end
68+
$Base.propertynames(what::$ename) = propertynames(what.nt)
69+
function $Base.getproperty(what::$ename, name::Symbol)
70+
if name == :nt
71+
getfield(what, name)
72+
else
73+
if hasproperty(what.nt, name)
74+
getproperty(what.nt, name)
75+
else
76+
getfield(Main, name)(what)
77+
end
78+
end
6979
end
80+
$ename{T}(what::$ename) where T = $ename{T}(what.nt)
81+
$ename{T}(;kwargs...) where T = $ename{T}((;kwargs...))
82+
$Base.show(io::IO, what::$ename{T}) where T = print(io, T, what.nt)
83+
$Base.merge(what::$ename, args...) = typeof(what)(merge(what.nt, args...))
84+
update(what::$ename; kwargs...) = merge(what, (;kwargs...))
85+
update(what::$ename, args...) = merge(what, (;zip(args, getproperty.([what], args))...))
86+
$Base.hash(what::$ename{T}, h::Int=0) where T = hash((what.nt, T, h))
7087
end
7188
end
72-
# DynamicObject{T}(nt::NamedTuple) where T = DynamicObject{T}(nt)
73-
DynamicObject{T}(what::DynamicObject) where T = DynamicObject{T}(what.nt)
74-
DynamicObject{T}(;kwargs...) where T = DynamicObject{T}((;kwargs...))
89+
90+
"""
91+
DynamicObject{T}
92+
93+
A `DynamicObject` is a thin named wrapper around a generic NamedTuple which enables function overloading.
94+
The type is inefficient computationally, but can enable more efficient prototyping/development.
95+
"""
96+
@dynamic_type DynamicObject
97+
# struct DynamicObject{T}
98+
# nt::NamedTuple
99+
# DynamicObject{T}(nt::NamedTuple) where T = new(nt)
100+
# end
101+
102+
# Base.propertynames(value::DynamicObject) = propertynames(value.nt)
103+
# function Base.getproperty(value::DynamicObject, name::Symbol)
104+
# if name == :nt
105+
# getfield(value, name)
106+
# else
107+
# if hasproperty(value.nt, name)
108+
# getproperty(value.nt, name)
109+
# else
110+
# getfield(Main, name)(value)
111+
# end
112+
# end
113+
# end
114+
# # DynamicObject{T}(nt::NamedTuple) where T = DynamicObject{T}(nt)
115+
# DynamicObject{T}(what::DynamicObject) where T = DynamicObject{T}(what.nt)
116+
# DynamicObject{T}(;kwargs...) where T = DynamicObject{T}((;kwargs...))
117+
# Base.show(io::IO, what::DynamicObject{T}) where T = print(io, T, what.nt)
118+
# Base.merge(what::DynamicObject, args...) = typeof(what)(merge(what.nt, args...))
119+
# update(what; kwargs...) = merge(what, (;kwargs...))
120+
# update(what, args...) = merge(what, (;zip(args, getproperty.([what], args))...))
121+
# Base.hash(what::DynamicObject{T}, h::Int=0) where T = Base.hash((what.nt, T, h))
122+
123+
124+
# function cached(what::DynamicObject, key)
125+
# if hasproperty(what, key)
126+
# # println("LOADING FROM DynamicObject")
127+
# getproperty(what, key)
128+
# else
129+
# if !isdir("cache")
130+
# mkdir("cache")
131+
# end
132+
# file_name = "cache/$(key)_$(what.hash)"
133+
# if isfile(file_name)
134+
# # println("LOADING FROM FILE!")
135+
# Serialization.deserialize(file_name)
136+
# else
137+
# # println("COMPUTING")
138+
# rv = getproperty(what, key)
139+
# Serialization.serialize(file_name, rv)
140+
# rv
141+
# end
142+
# end
143+
# end
75144

76145
# DynamicObject{T}() where T = DynamicObject{T}(NamedTuple())
77146
# default(what, name) = missing
78147
# getprop(what, name, def=default(DynamicObject, name)) = hasproperty(what, name) ? getproperty(what, name) : def
79-
Base.show(io::IO, what::DynamicObject{T}) where T = print(io, T, what.nt)
80-
Base.merge(what::DynamicObject, args...) = typeof(what)(merge(what.nt, args...))
148+
81149
# Base.length(what::DynamicObject) = 1
82150
# Base.size(what::DynamicObject) = ()
83151
# Base.getindex(what::DynamicObject, i) = what
84152
# Base.iterate(what::DynamicObject) = iterate([what])
85153
# Base.merge(what::DynamicObject, arg1::DynamicObject, args...) = typeof(what)(merge(what.nt, arg1.nt, args...))
86154
# igetproperty(obj, sym) = getproperty(obj, sym)
87155
# igetproperty(obj, sym, args...) = igetproperty(getproperty(obj, sym), args...)
88-
update(what; kwargs...) = merge(what, (;kwargs...))
89-
update(what, args...) = merge(what, (;zip(args, getproperty.([what], args))...))
90156
# update_default(what, args...) = update(wha)
91157

92158
# what = DynamicObject
93-
Base.hash(what::DynamicObject{T}, h::Int=0) where T = Base.hash((what.nt, T, h))
94-
95-
function cached(what::DynamicObject, key)
96-
if hasproperty(what, key)
97-
# println("LOADING FROM DynamicObject")
98-
getproperty(what, key)
99-
else
100-
if !isdir("cache")
101-
mkdir("cache")
102-
end
103-
file_name = "cache/$(key)_$(what.hash)"
104-
if isfile(file_name)
105-
# println("LOADING FROM FILE!")
106-
Serialization.deserialize(file_name)
107-
else
108-
# println("COMPUTING")
109-
rv = getproperty(what, key)
110-
Serialization.serialize(file_name, rv)
111-
rv
112-
end
113-
end
114-
end
115159
# update_cached(what, args...) = merge(what, (;zip(args, cached.([what], args))...))
116160
# Plots.plot!(p, what) = Plots.plot()
117161
# Plots.plot(what::DynamicObject{T}) where T = Plots.plot!(Plots.plot(), what)

0 commit comments

Comments
 (0)