tdu.Dependency tutorial - 2022-07-31 00:23

Hey, sorry everyone for not responding. I’m not visiting very often. I’ll take a look when I have a minute

@Ivan please may I also ask what is the logic behind order of extension initializations? I haven’t thought about this much in the past, but this dependency-oriented topic made me think a lot about this. Are there some rules that define this initialization order on startup? Thanks

Extensions are initialized on demand. That means the first time something tries to access them, they are compiled. This can sometimes be hard to predict because of TouchDesigner’s on-demand cook system. You can force them to initialize on startup with the onStart method in executeDAT.

We have had discussions about making this more clear in the future.

I see, thanks for info. Does it mean that onStart in executeDAT gets executed before any extension actually initializes? (So that one could rest assured initialization order defined by executeDAT will always be the same - meaning no extension could initialize before executeDAT?)

@densi nice - wasn’t aware of these new dependency callbacks until now, very useful.

curious, how are you getting VS Code to recognize TD context via - import td, import tdu

currently - i’m achieving this by pointing to the stubs from @tekt (td-components/lib/_stubs at master · optexture/td-components · GitHub) in my VS Code settings -

python.autoComplete.extraPaths
python.analysis.extraPaths

and then importing via - try: op except: from _td import *

however, wondering if there’s an alternative i’m not aware of - thanks.

Hey! Unfortunately there isn’t a way to make intellisense aware of td methods since all modules td uses aren’t available as source py files. What I’m doing here it’s just a type hinting, it seems to work somehow. You can google for python type hints to get the idea.

1 Like

@monty_python

Does it mean that onStart in executeDAT gets executed before any extension actually initializes?

It should work that way. But if something in your onStart causes something else to initialize the order could still get funky

1 Like

Hello @Ivan, please may I ask whether you found some hack that would allow creation of non-dead weakrefs?

Sorry I’m not sure the context here. I can tell you in general there is no way to create non-dead weakrefs if an object is temporary and has nothing else referring to it. Without seeing your specific problem, my advice would be to create regular refs and destroy them as needed!

I was referring to this scenario we have discussed previously.

Based on this I was under impression weakrefs should work there, but there was something wrong going on.

Does it mean one shouldn’t use weakrefs in such scenarios? Thanks :slight_smile:

Ah yes! Sorry, so many pans on the fire.

I can dig into this more this week. If you have time to make things faster, if you can make the simplest possible example of the situation with no other tutorial stuff around it, that would save a step for me.

Either way, I’ll put this on my todo list to revisit this week.

So, yeah, unfortunately the way that is being done, the references are going to die immediately.

To solve this problem, in our next experimental extensions can have a delTD function that you can use for cleanup, eliminating the need to use a weakref here. This function will be called whenever extensions are reinitialized on a component, whether they are garbage collected or not.

Aha, that sounds interesting. If I understand this correctly, delTD would cleanup old instances of extension classes that weren’t garbage collected (possibly due to some reference keeping them alive)? Anyway I am curious to try this out once new experimental series roll out. Thanks :slight_smile:

Just to give a preview, the __delTD__ function is similar to the Python __del__ except it won’t depend on the garbage collector. You’ll get the function call when TouchDesigner reinitializes the extension… meaning you’ll have a chance to do any cleanup necessary to allow the actual __del__ function to run.

Now I get it. :slight_smile: That sounds great, thanks.

Thinking about this further, I wanted to also ask how would you go about maintaining list of observers between subject’s re-inits?

Example 1 (re-init of observer - working thanks to new delTD)
Lets say one would use delTD on observer to remove its method from subjects dependency callbacks.
Observer would be then garbage collected and new instance will be created (again adding its method to subjects dependency callbacks). This sounds all good to me.

Example 2 (re-init of subject - working, but observers are lost)
However what happens when subject is re-initialized? Lets say there are ten observers in subject’s dependency callbacks before it is destroyed and recreated. New instance of course lacks knowledge about these ten observers, which breaks their updates. Please what would be your approach to keeping this information? Thanks.

Also I wanted to ask whether you think delTD might also find its way back to current stable branch, or would it be too risky to do?

Oh, I think I got it - pretty simple actually. The subject should emit some event during its __del__ on all observers (telling them to re-subscribe themselves to subject). This way new instance of subject should get all observers back right away. :slight_smile:

Subject sending an event to resubscribe is exactly what we are looking at, yes. The details are not fleshed out.

Considering that this is still being designed and experimental is coming soon, it’s unlikely that this will end up in current official. Not impossible but unlikely.

In the meantime you can use opexecDAT to watch for extensions being reinitialized and then resubscribe. Clunky but it should work.

1 Like

Thank you very much for info. I didn’t know experimental will be coming soon, that’s great. :partying_face:

Hello @Ivan,
thank you very much for bringing __delTD__ to current stable branch. I have been playing with it just now and it solved the problem - observer references can now be properly cleaned up from subject, which is great :slight_smile:

I am attaching a simple example if someone might want to take a look.

observer_pattern_using_delTD.4.toe (4.6 KB)

One thing I have noticed while playing with it, is that observer’s __del__ sometimes doesn’t get called. It seems like its reference is properly removed from the subject, so I am not sure why it might be happening, but I have seen it couple times now.

in observer __delTD__
unregistering observer from subject
in observer __init__
registering observer to subject

Unfortunately I wasn’t able to isolate some reproducible steps, but I will post here in case I happen to find some pattern that would trigger it.