Notifications
Clear all

[Closed] How does this work?

Ok! Strange thing happened to me. I was working today and got annoyed by having to double click on the root link of a biped to get all the children, so I wrote a script to get all the children of the selected object. When I wrote it, it felt like the best way to do things, and it works.
However, in coming back to the script a couple of hours later to implement it elsewhere, I can’t comprehend how its working! It seems like it shouldn’t work, and its properly iterating over every child of the selection, and the children of its children, etc. The thing is, I can’t find where this recursion is happening, even after writing some debug prints into the code. I think its happening in the += operator, but I still don’t follow it. If one of you guys would be so kind as to analyze this small piece of code for our educational benefit, I’d much appreciate it:


  (
  	fn getChildren nodes =
  	(
  		local nodeArray = #()
  		
  		for o in nodes do
  			nodeArray += for c in o.children collect c
  			
  		nodeArray
  	)
  	
  	select (getChildren $)
  )
  
4 Replies
1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

Oh! A puzzle!

Truth is, your code does no recursion. MAXScript does.
Select the Pelvis of your Biped and run this:

selection.count
–> 1
(for o in selection collect o).count
–> 1
(for o in $ collect o).count
–> 34 (!!?)

Now select the right clavicle and run the same:
(for o in $ collect o).count
–> 6

As you can see, iterating through the $ selection iterates through all its children automatically, without any additional code. So your function could only do that and you would always select the correct children:

fn selectChildren =
(
select (for o in $ collect o)
)
selectChildren ()

This is some strange side-effect of using the ‘$’ instead of ‘selection’. Same is true for RingArray (when you select the dummy) and other Systems, Groups and ANY other hierarchy – selecting the parent and running the above code selects all children.

I am not even sure this is documented anywhere. If it is not, it will be next time…

While this is not technically recursive, you are starting at the top of the hierarchy and adding members to the array. So, say you pass $Bip01 into the function. In the first iteration of the nodes collection you are adding the children of $Bip01. So the array is now #($Bip01_Footsteps, $Bip01_Pelvis). The collection iteration continues, first with the footsteps and the the pelvis. This will add the children of the pelvis, making the array larger. The iteration continues, now checking each of the children of the pelvis that have been added to the array and adding those children–making the array larger.

So forth and so on, each time making the array larger and causing the iteration to loop over the new objects that have been added to the array one at a time.

This only works because you are appending objects to the end of the array. If you were instead inserting the items into the beginning of the array, the function would not behave as you expect.

Thanks guys!

Bobo, I never knew $ had that quality!  That's what threw me off, thanks a bunch :thumbsup:

EDIT: As a side note, doing this test:


   (for o in selection[1] collect o).count ==   (for o in $ collect o).count
   

returns a “true” value. I assume this is because, internally, if a single object is selected, accessing it as an index in the selection virtual array is the exact same as accessing it through $, subsequently all its children are counted as well…

I should have checked my assumption before I posted a comment. Thanks for the reply, Bobo.