Modifying internal fields inside a nested hierarchy

Suppose I have the following situtation with a nested hierarchy:

julia> mutable struct Foo
           x
       end

julia> struct Bar
           y::Vector{Foo}
       end

julia> b = Bar([Foo(1), Foo(2)])
Bar(Foo[Foo(1), Foo(2)])

julia> function modify!(b::Bar, w, structure)
      ## what should go here?
       end
modify! (generic function with 1 method)

I would like to write the function modify! to modify the internal elements of the Foo objects by replacing them with the values inside the Vector w.

The catch is that modify! should not need to know anything about the internal structure. Rather I would like to pass in a structure thing like a Vector of Refs that point to the internal elements that I want to change. But a Vector of Refs doesn’t seem to work.

Is there a solution to this?

(This is simplified from a real problem with a deeper hierarchy. The modify! function needs to work on objects with different internal structures.)

Some resources

5 Likes

there’s a lot of ways to do it… It’s not fun unless this is how your brain works! I wrote a decision tree method like this and it was hideously slow, although elegant via LOC. Julia just doesn’t like function calls on deeply recursive structs :/. I think the tidy solution is to break out the structure into a graph where each node is the same type for traversing the hierarchical mess, and has pointers to the actual object which is in some sort of a hashed list or something. I’d love to hear a counter argument to that, because this has befuddled me!

Anyways, an easy way, without restructuring things, would be to write a recursive function that scans a struct for depth and type and modifies as it goes. You can make a modify function that traverse the nodes recursively or using a while loop or whatever, checks the reference state modifies in place and keeps going. Maybe something like this(not real code)? dunno

fn = x -> istype(x, Array) ? push!(x, "123") : x

function modify(NestedMess::Any, fn) 
  if terminal node
         fn(node)
         return nothing
   else  
         modify.(NestedMess, fn)
    end
end

The alternative is to know exactly where you wish to modify certain things in the struct (not so fun).