-
-
Save dom96/1984a7a196dddd658c2f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import strutils | |
type | |
NodeKind = enum | |
NodeKind1, NodeKind2, NodeKind3 | |
# Only some Nodes should have children. You can't name two attributes within a | |
# type definition using a case statement the same as of yet (probably a bug). | |
# You will get a redefinition error for the attribute, even though both | |
# branches are never active at the same time. | |
Node = ref object | |
value: string | |
case kind: NodeKind | |
of NodeKind1: | |
internalChildren: ref seq[Node] | |
of NodeKind2: | |
internalChildren2: ref seq[Node] | |
of NodeKind3: | |
something: string | |
# So we write a custom accessor to transparently grab the correct children | |
# attribute for the Node | |
proc children(node: Node): ref seq[Node] = | |
case node.kind: | |
of NodeKind1: | |
return node.internalChildren | |
of NodeKind2: | |
return node.internalChildren2 | |
else: | |
raise newException(ValueError, "$1 can't have children".format(node.kind)) | |
proc newNode(kind: NodeKind, value: string): Node = | |
new result | |
result.kind = kind | |
result.value = value | |
case kind | |
of NodeKind1: | |
new(result.internalChildren) | |
result.internalChildren[] = @[] | |
of NodeKind2: | |
new(result.internalChildren2) | |
result.internalChildren2[] = @[] | |
of NodeKind3: | |
result.something = "" | |
proc main() = | |
var node = newNode(NodeKind1, "Hello World") | |
let childNode = newNode(NodeKind1, "Child 1") | |
node.internalChildren[].add childNode | |
# Works exactly as expected! But we have to use internalChildren and | |
# internalChildren2 depending on type. Now let's attempt to use our accessor | |
# proc to hide that complexity from us | |
echo node.repr | |
# This calls the children proc and returns the children field of the given | |
# nide. | |
var referenceToChildren = node.children | |
let childNode2 = newNode(NodeKind1, "Child 2") | |
referenceToChildren[].add childNode2 | |
# Child 2 doesn't appear in the object structure, apparently node.children | |
# returned a copy of the seq[Node]-children data structure and modified it | |
# instead of the original object | |
echo node.repr | |
# Output: | |
discard """ | |
ref 00328028 --> [value = 00329028"Hello World", | |
NodeKind1internalChildren = 00329048[ref 00328040 --> [value = 00328058"Child 1", | |
NodeKind1internalChildren = 0032a038[]]]] | |
ref 00328028 --> [value = 00329028"Hello World", | |
NodeKind1internalChildren = 00329048[ref 00328040 --> [value = 00328058"Child 1", | |
NodeKind1internalChildren = 0032a038[]]]] | |
""" | |
when isMainModule: | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment