Skip to content

Commit 4d945ac

Browse files
committed
docs: improve description of get_children
1 parent edc1981 commit 4d945ac

File tree

4 files changed

+51
-40
lines changed

4 files changed

+51
-40
lines changed

docs/src/api.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ right_child = get_child(tree, 2)
101101

102102
set_child!(tree, new_child, 1)
103103

104-
children = get_children(tree)
105104
left, right = get_children(tree, Val(2)) # type stable
106105

107106
# Transform to ternary operation

src/Node.jl

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ for N in (:Node, :GraphNode)
8989
end
9090
end
9191

92-
#! format: off
9392
"""
9493
Node{T,D} <: AbstractExpressionNode{T,D}
9594
@@ -135,7 +134,6 @@ in the `allocator` keyword argument.
135134
"""
136135
Node
137136

138-
139137
"""
140138
GraphNode{T,D} <: AbstractExpressionNode{T,D}
141139
@@ -184,21 +182,33 @@ function poison_node(n::AbstractNode)
184182
return n
185183
end
186184

185+
"""
186+
get_children(node::AbstractNode)
187+
188+
Return the raw `.children` tuple of a node. Some of these
189+
children may be "poisoned" nodes which you should not access,
190+
as they will trigger infinite recursion errors. Ensure to
191+
only access children only up to the `.degree` of the node.
192+
"""
187193
@inline function get_children(node::AbstractNode)
188194
return getfield(node, :children)
189195
end
190196

191197
"""
192-
get_children(node::AbstractNode)
198+
get_children(node::AbstractNode, n::Integer)
193199
get_children(node::AbstractNode, ::Val{n})
194200
195-
Return the children tuple of a node. The first form returns the complete children tuple as stored.
196-
The second form returns a tuple of exactly `n` children, useful for type stability when the
197-
number of children needed is known at compile time.
201+
Return a tuple of exactly `n` children of the node. You should
202+
use the `.degree` field of a node to determine the number of children
203+
to return. Typically this is done within a `Base.Cartesian.@nif` statement
204+
for total type stability.
198205
"""
199-
@inline function get_children(node::AbstractNode, ::Val{n}) where {n}
206+
@inline function get_children(node::AbstractNode{D}, n::Integer) where {D}
207+
return get_children(node, Val(n))
208+
end
209+
@inline function get_children(node::AbstractNode{D}, ::Val{n}) where {D,n}
200210
cs = get_children(node)
201-
return ntuple(i -> cs[i], Val(Int(n)))
211+
return ntuple(i -> cs[i], Val(n))
202212
end
203213

204214
"""
@@ -207,7 +217,7 @@ end
207217
Return the `i`-th child of a node (1-indexed).
208218
"""
209219
@inline function get_child(n::AbstractNode{D}, i::Int) where {D}
210-
return get_children(n)[i]
220+
return get_children(n, i)
211221
end
212222

213223
"""
@@ -227,7 +237,9 @@ end
227237
Replace all children of a node with the given tuple. If fewer children are
228238
provided than the node's maximum degree, remaining slots are filled with poison nodes.
229239
"""
230-
@inline function set_children!(n::AbstractNode{D}, children::Union{Tuple,AbstractVector{<:AbstractNode{D}}}) where {D}
240+
@inline function set_children!(
241+
n::AbstractNode{D}, children::Union{Tuple,AbstractVector{<:AbstractNode{D}}}
242+
) where {D}
231243
D2 = length(children)
232244
if D === D2
233245
n.children = children
@@ -243,37 +255,39 @@ provided than the node's maximum degree, remaining slots are filled with poison
243255
end
244256

245257
macro make_accessors(node_type)
246-
esc(quote
247-
@inline function Base.getproperty(n::$node_type, k::Symbol)
248-
if k == :l
249-
# TODO: Should a depwarn be raised here? Or too slow?
250-
return $(get_child)(n, 1)
251-
elseif k == :r
252-
return $(get_child)(n, 2)
253-
else
254-
return getfield(n, k)
255-
end
256-
end
257-
@inline function Base.setproperty!(n::$node_type, k::Symbol, v)
258-
if k == :l
259-
if isdefined(n, :children)
260-
$(set_child!)(n, v, 1)
258+
esc(
259+
quote
260+
@inline function Base.getproperty(n::$node_type, k::Symbol)
261+
if k == :l
262+
# TODO: Should a depwarn be raised here? Or too slow?
263+
return $(get_child)(n, 1)
264+
elseif k == :r
265+
return $(get_child)(n, 2)
261266
else
262-
$(set_children!)(n, (v,))
263-
v
267+
return getfield(n, k)
264268
end
265-
elseif k == :r
266-
$(set_child!)(n, v, 2)
267-
else
268-
T = fieldtype(typeof(n), k)
269-
if v isa T
270-
setfield!(n, k, v)
269+
end
270+
@inline function Base.setproperty!(n::$node_type, k::Symbol, v)
271+
if k == :l
272+
if isdefined(n, :children)
273+
$(set_child!)(n, v, 1)
274+
else
275+
$(set_children!)(n, (v,))
276+
v
277+
end
278+
elseif k == :r
279+
$(set_child!)(n, v, 2)
271280
else
272-
setfield!(n, k, convert(T, v))
281+
T = fieldtype(typeof(n), k)
282+
if v isa T
283+
setfield!(n, k, v)
284+
else
285+
setfield!(n, k, convert(T, v))
286+
end
273287
end
274288
end
275-
end
276-
end)
289+
end,
290+
)
277291
end
278292

279293
# @make_accessors Node{T,2} where {T}

src/ParametricExpression.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import ..NodeModule:
1616
with_default_max_degree,
1717
max_degree,
1818
preserve_sharing,
19-
get_children,
20-
set_children!,
2119
leaf_copy,
2220
leaf_convert,
2321
leaf_hash,

test/test_n_arity_nodes.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ end
507507
p = Node{Float64,3}(; op=1, children=(c1, c2, c3))
508508

509509
@test p isa Node{Float64,3} # new type parameter D shows up
510-
@test get_children(p) == (c1, c2, c3)
510+
@test get_children(p, Val(3)) == (c1, c2, c3)
511511
@test get_child(p, 2) === c2
512512
@test get_children(p, Val(1)) === (c1,) # Val-specialised accessor
513513
@test_throws BoundsError get_child(p, 4)

0 commit comments

Comments
 (0)