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.
 


Reply via email to