Hi, I have quite a complex couple of functions and a long winded problem,
I'll be as clear as I can be. I have a function, which builds up composite
types based on the contents of a data file (XML). I use a recursive
function to do this: (Note it's not 100% finished but it does successfully
crawl the XML tree and create the basic structure and composite types, by
starting at the element, building the required type from the info at that
element, and then calling the same function recursively on all the children:
# xmlclade is a type from LightXML, cladeArray is the variable of interest
and is what contains the results of each recursive call to this function.
currentClade is a composite type containing an integer and so is mutable,
it is used in recursive calls to the functions.
function recursiveBuild(xmlclade, cladeArray, currentClade,
parentClade::Int)
# Update the node tracker.
currentClade.nodeIndex += 1
current = currentClade.nodeIndex # Initialize a local variable called
current, taken from the currentClade variable to keep as the variable to
pass to furthur recursive calls as the parent index.
# Get name of clade element.
label = ""
isroot = currentClade == 0 ? true : false
children = get_elements_by_tagname(xmlclade, "clade")
istip = length(children) == 0 ? true : false
# Make the clade object by calling the constructor.
cladeArray[currentClade.nodeIndex] = PhyXElement(label, isroot, istip,
parentClade)
for i in children
recursiveBuild(i, cladeArray, currentClade, current)
end
end
If I use this function, the cladeArray array is properly fleshed out with
the types generated from the read in information. This type is the
PhyXElement type as can be seen from the constructor, it takes 4 argument
and the type contains 4 variables.
However PhyXElement can be extended to contain more than those 4 variables.
So I modified the above function with two macros that can alter the code
accordingly. It is below, but not since they are not provided any
arguments, the result should be functionally identical to the above
definition:
macro gatherPhyXMLAttributes(attributes...)
code = :(begin end)
for i in attributes
push!(code.args, :($(symbol("$i = readPhyXML(xml, ::$i)"))))
end
code
end
macro makePhyXElement(attributes...)
line = "cladeArray[currentClade.nodeIndex] = PhyXElement(label, isroot,
istip, parentClade"
for i in attributes
line = "$(line), $i"
end
:($(symbol("$(line))")))
end
function recursiveBuild(xmlclade, cladeArray, currentClade, parentClade::Int
)
# Update the node tracker.
currentClade.nodeIndex += 1
current = currentClade.nodeIndex # Initialize a local variable called
current, taken from the currentClade variable to keep as the variable to
pass to furthur recursive calls as the parent index.
# Get name of clade element.
label = ""
isroot = currentClade == 0 ? true : false
children = get_elements_by_tagname(xmlclade, "clade")
istip = length(children) == 0 ? true : false
# Get and process all additional data....
@gatherPhyXMLAttributes
# Make the clade object by correctly calling the constructor.
@makePhyXElement
for i in children
recursiveBuild(i, cladeArray, currentClade, current)
end
end
If I now expand the function definition using macro expand the function
body is:
currentClade.nodeIndex += 1 # line 4:
current = currentClade.nodeIndex # line 6:
label = "" # line 7:
isroot = if currentClade == 0
true
else
false
end # line 8:
children = get_elements_by_tagname(xmlclade,"clade") # line 9:
istip = if length(children) == 0
true
else
false
end # line 11:
begin
end # line 12:
cladeArray[currentClade.nodeIndex] = PhyXElement(label, isroot,
istip,parentClade
) # line 13:
for i = children # line 14:
recursiveBuild(i,cladeArray,currentClade,current)
end
So what has happened is the first macro made the rather useless "begin end"
lines, which would contain additional operations if the macro received
arguments. The second macro without arguments recreates the call to the
PhyXElement constructor. However if I run this version of the function, the
cladeArray array remains an array of undefined element and is not filled in
with PhyXElement types as it is when the previous version of the function
is used. I wondered if the issue is to do with macro hygiene but I can't
see it. I hope someone can look at how I've written this and see if I've
made a derp - Arrays are mutable so I figured cladeArray should end up the
same as it did when the previous version of the function is used.
Thanks,
Ben.