question

Tom S4 avatar image
0 Likes"
Tom S4 asked Jordan Johnson commented

Bind ODT within object

What is the preferred way to bind an object as variable within another object?

I'm looking at the PF resource object and how it has an internal list. In the resource class, it looks like it might initially bind it as a node:

FlexSim::TreeNode* list = 0

In the PF library tree, it does not already have the list object created or even a placeholder for 'list'. I'm assuming the magic happens in Resource::onCreate().

My working solution is the following:

treenode myobjectcontainer;
...
// bind container object as a treenode
void MyPFObject::bindVariables() {
   bindVariable(myobjectcontainer);
}
...
// create instance of object (delay, for example), inside my bound container
void MyPFObject::onCreate() {
   treenode newobject = createinstance(library().find("?Delay"), myobjectcontainer);
}

// referencing would be something like this:
myobjectcontainer->subnodes[1]->objectAs(Delay)->doStuff();

Maybe another option would be to save defaults with an instance of the object already loaded into my library object. I'm wondering what is generally the preferred way.

FlexSim 23.0.1
module sdkbind variable
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

1 Answer

Jordan Johnson avatar image
0 Likes"
Jordan Johnson answered Jordan Johnson commented

Your guesses are pretty much correct. Here's how the Process Flow List includes a regular list inside itself:

  1. Bind a TreeNode* as a variable (called "list" in the case of the PF List).
  2. In OnCreate, destroy the node if it's present. It should be, because of how bind() works, but it's not a node with List data on it yet.
  3. Also in OnCreate, create a new thing. In the case of the PF list, it uses Tools::create() to create a new list in the toolbox, and then transfers that list into its variables node.
  4. Once transferred in, set the "list" variable to point at the node you just added.
  5. In the OnReset of the owning object, be sure to call OnReset for the internal object. This is important because the normal OnReset calls don't dive inside object attributes, so you have to manually call OnReset yourself.
· 2
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Tom S4 avatar image Tom S4 commented ·

Thanks for the overview. This worked great.

Can internal objects/activities still be used by their owning objects as if they were created normally?

For instance, modifying the example above,

treenode myinternaldelay = 0;

void MyPFObject::onCreate() {
   myinternaldelay->destroy();
   treenode newobject = createinstance(library().find("?Delay"), this->holder->find("variables"));
   myinternaldelay = newobject;
   myinternaldelay.setName("myinternaldelay");
}
 
/* This is a problem */
void MyPFObject::onBlockingStart(Instance* instance, Token& token)
{
   myinternaldelay->objectAs(Delay)->start(instance, token); // <-- here
}

produces:

exception: Exception caught in start() of activity "myinternaldelay" in process flow "". Continuing throw...
exception: Exception caught in onStart() of activity " in "ProcessFlow". Continuing throw...
exception: Exception caught in Executive::processeventinlist().

I'd imagine it has to do with the activity not having the context/view of a ProcessFlow object, but I'm not quite sure if it can be done in this way. If not, I'm considering breaking this out into a global flow somewhere hidden from the user.

0 Likes 0 ·
Jordan Johnson avatar image Jordan Johnson ♦♦ Tom S4 commented ·

My guess is that Activities or other Process Flow blocks cannot be used internally. I think their code assumes that they are a child node of the Process Flow.

If your goal is to call other activities, then consider an approach like the People module, where activities inherit the Run Sub Flow activity, and call specific flows that the module adds to each model.

1 Like 1 ·