Notifications
Clear all

[Closed] Evaluate CTD suckage

This works:


--other stuff goes here
temp = topoOps.getSortedConnectedVerts obj1 obj2 startVert1 startVert2
arrOps.joinIfUnique obj1VertArr temp[1]
arrOps.joinIfUnique obj2VertArr temp[2]
for j = 1 to temp[1].count do	--in the array of sorted/connected verts, 
(
	temp2 = topoOps.getSortedConnectedVerts obj1 obj2 temp[1][j] temp[2][j]
	arrOps.joinIfUnique obj1VertArr temp2[1]
	arrOps.joinIfUnique obj2VertArr temp2[2]
	
	for k = 1 to temp2[1].count do
	(
		temp3 = topoOps.getSortedConnectedVerts obj1 obj2 temp2[1][k] temp2[2][k]
		arrOps.joinIfUnique obj1VertArr temp3[1]
		arrOps.joinIfUnique obj2VertArr temp3[2]
		
		for l = 1 to temp3[1].count do
		(
			temp4 = topoOps.getSortedConnectedVerts obj1 obj2 temp3[1][l] temp3[2][l]
			arrOps.joinIfUnique obj1VertArr temp4[1]
			arrOps.joinIfUnique obj2VertArr temp4[2]
			
			for m = 1 to temp4[1].count do
			(
				temp5 = topoOps.getSortedConnectedVerts obj1 obj2 temp4[1][m] temp4[2][m]
				arrOps.joinIfUnique obj1VertArr temp5[1]
				arrOps.joinIfUnique obj2VertArr temp5[2]
			)
		)
	)
)

This does not:


struct topologyOps
(
--other functions
	fn recurseConnectedVerts obj1 obj2 prevTemp obj1VertArr obj2VertArr =
	(
		for i = 1 to prevTemp[1].count do
		(
			local temp = topologyOps.getSortedConnectedVerts obj1 obj2 prevTemp[1][i] prevTemp[2][i]
			--arrOps.joinIfUnique obj1VertArr temp[1]
			--arrOps.joinIfUnique obj2VertArr temp[2]
			topologyOps.recurseConnectedVerts obj1 obj2 temp obj1VertArr obj2VertArr
		)
		
	)
)

global topoOps = topologyOps()

--other stuff goes here

temp = topoOps.getSortedConnectedVerts obj1 obj2 startVert1 startVert2
arrOps.joinIfUnique obj1VertArr temp[1]
arrOps.joinIfUnique obj2VertArr temp[2]

topoOps.recurseConnectedVerts obj1 obj2 temp obj1VertArr obj2VertArr

So this is a two parter:

  1. Is there rhyme or reason for MXS’s recursive function CTD suckage? I’ve run into this for recursive functions in other cases- when does max decide to CTD (no error report)? Any consistent reasons why?
  2. Is there a way to debug/track this? I’ve eliminated the joinIfUnique function and it still CTD’s… I’ve tried using the debugger, but it CTD’s along with Max, so I can’t see what it is getting hung up on or what its last words were, AFAIK.

Normally I can get around the CTD’s, or find out what the problem is, but I’ve been stuck on this for a couple hours and have had no luck.

7 Replies
 JHN

Had to look up what CTD was, but I think you’re meaning Crash To Desktop here

I think the problem with nr 2 is that you’re trying to recurse with

topologyOps.recurseConnectedVerts

but you instanced a struct named: topoOps

A function in an instance has no knowledge of it’s own name (in that way it differs from real classes and objects in OOP languages). If you cal topoOps.recurseConnectedVerts I bet it works, but I understand it’s not what you want, because it’s messy. Some thoughts and the real pro’s should comment on this… you can pass a struct to itself in a variable for example, letting you use a local variable in the struct to “reference back” the struct functions. A non instanced struct cannot access it’s sibling functions since it’s behaving more like a namespace and an instanced object has no relation to it’s struct definition (class)… So it’s suckage all over, and no easy/right way out IMO. Max should have some better class/object implementation someway…

Hope someone can add to this…
-Johan

The way I understand it, you can access functions from a struct definition without it being instanced. And referencing other struct functions within a struct has always worked fine for me (calling them from the instance can lead to scope problems where the instance is defined after the struct). I suppose this may cause an issue with recursive functions, but it hasn’t seemed to yet.

Anyway, I tried using the instaced functions, CTD’d. I tried taking the functions out of the struct and just using them, it still CTD’d. I am quite sure the problem doesn’t have to do with scopes/namespace. The problem probably stems to something I’m doing in one of the functions I didn’t give the source to, which Max doesn’t like in a recursive context. I’m more concerned with why this constantly seems to happen. I have a couple workarounds I will try tomorrow as well.

That’s a really interesting issue you are having there. Several things jump immediately to mind (now I have no idea about the internals of max so I could completely off the mark)…

  1. It might be that max is having to create a “temporary” instance of the struct in order to call it (on each iteration) – personally, I doubt it, as you don’t have access to the internal variables when accessing a struct in this manner…and to be honest, it would only ever need one reference (outside the normal instances)

  2. If you have an instance of the struct, you don’t need to call it’s functions by the struct name (ie you shouldn’t need to call “topologyOps.recurseConnectedVerts”, you should be able to call the function directly…) Obviously, if you weren’t going to use a instance, then you would…

The only (major) difference I can see is, in your first example, you are using the instance of struct when calling you functions and in the second your using the static reference…

Don’t know if that helps…and I’d be interested in knowing more (as I use structs like this all the time)…

Shane

I’m not 100% sure what the original intent was, but you can mimic static member variables of c++ classes by exploiting the fact that a copy of a struct instance is only a ‘shallow’ copy. Any array or struct elements of the original are simply referenced by the new copy.


      struct shared_data
      (
      	calls = 0
      )
      
      struct recursiveOps
      (
      	calls = 0,
      	
      	shared = shared_data(),
      	
      	fn recursiveCall n =
      	(
      		format "recursiveCall call % % %
" n calls shared.calls	
      		calls += 1
      		shared.calls += 1
      		
      		for i = 1 to n do
      		(
      			recursiveCall (n-1)
      		)
      	)
      		
      )
      
      -- Create an instance
      recOps1 = recursiveOps()
      
      -- Copy the instance so that 'shared' references the same instance of 'struct_data'
      recOps2 = copy recOps1
      
      recOps1.recursiveCall 3
      recOps2.recursiveCall 2
      
      format "Instance 1 made % calls with % shared calls
" recOps1.calls recOps1.shared.calls
      format "Instance 2 made % calls with % shared calls
" recOps2.calls recOps2.shared.calls
      
      
This yields:

Instance 1 made 16 calls with 21 shared calls
Instance 2 made 5 calls with 21 shared calls

Some very interesting thoughts about structs in this thread. I am going to bookmark it for that reason (really cool ideas and workarounds). However, as I said in my above post, I got rid of the struct entirely and just have global functions now, and it still CTD’s.

I’ll make sure to post here if I find out anything or deduce why max likes to CTD so much with recursive functions (I think the problem is with recursion, and not with the structs, since I got rid of the structs and it still breaks).

EDIT: My feeling is I’m just confusing max and it is committing suicide.

Does it always die, or only on complex / large objects?

Can always create a file and format all of the function parameters to that, include a new depth parameter that you increase each for each recursion; see what that log file looks like by the time max goes poof. Usually a recursion crash is from it being an infinite recursion.

Yeah, it is getting caught in an infinite recursion. Doh!