Level: advanced
Sometimes it is desirable to use direct atom referencing instead of referencing via channels. So how can this be achieved?
In order to make pointer referencing work, we first need to understand the nature of pointers. So, what are pointers?
The pointer value is a large integer value, issued automatically by ED to each atom whenever it is created. So, for example, when a user drags a Server-atom into the model, an instance of the Server-atom is created (the new instance is visually represented in the model, while the original Server-atom is still sitting in the library tree). This new instance gets its own unique pointer value. This value is used by ED internally to uniquely identify this new atom. Note, the key word here is “unique”, which is a very nice feature that can come in handy when building models. So let’s try utilizing this ED functionality.
In order to make pointer referencing work, we need to take care of the following things:
1) Each atom needs to have a reference to a related atom
2) Update the pointer values when the related atom is created (think of saving and reopening of a model)
Let’s say that we have an atom named “Worker” which needs to have the following references:
• A reference to its schedule (an atom containing the table with times the worker works)
• A reference to a team that the worker belongs to
Now, let’s add attribute “Schedule” and attribute “BelongsToTeam” and make the following functions:
Worker_GetSchedule(e1)
Code: Select all
vtp(Att([Schedule], p(1)))
Code: Select all
Att([Schedule], p(1)) := p(2)
Code: Select all
vtp(Att([BelongsToTeam], p(1)))
Code: Select all
Att([BelongsToTeam], p(1)) := p(2)
Code: Select all
Dim([atmMotherWorker], vbAtom, c)
Worker_Create(e1, e2)
Code: Select all
Do(
Var([atmContainer], vbAtom, p(1)), {this is the atom, the worker will physically be placed in}
Var([atmTeam], vbAtom, p(2)),
Var([atmNewWorker], vbAtom),
Var([atmSchedule], vbAtom),
atmNewWorker := CreateAtom(atmMotherWorker, atmContainer),
Worker_SetBelongsToTeam(atmNewWorker, atmTeam),
Team_AddWorker(atmTeam, atmNewWorker),
{ create subatom }
atmSchedule := CreateAtom(Baseclass, atmNewWorker, [Schedule]),
Worker_SetSchedule(atmNewWorker, atmShedule)
)
Now, whenever we want to view the schedule of the worker or get its team, we merely need to call the appropriate Get-method.
However, if we would try to save the model containing some workers, schedules and teams and would want to reopen it, we would find out that the references within the attributes are no longer valid. This is the case, since ED automatically assigns new pointer values to the atoms upon their creation. There is no way we can override this functionality. However, we can update the attributes “Schedule” and “BelongsToTeam” to match the new pointer values. For this we need to do the following:
1) Adjust the save-model-functionality so that, prior to saving, each atom will saves its pointer value into the “ptrName”-attribute. For this, the following code can be used.
Code: Select all
ForAtomTreeUnder(
Model,
Do(
Sets,
if(
Not(AttributeExists(s, [ptrName])),
AddAttribute(s, [ptrName])
),
Att([ptrname], s) := String(s)
)
)
UpdatePointerReferences()
Code: Select all
Do(
var([atmTemporaryLookupTable], vbAtom),
var([atmTreeAtomBeingScanned], vbAtom),
var([valNrOfAtomsinModel], vbValue, 0),
var([valCounter], vbValue, 0),
var([valMinimumPointerValue], vbValue, 0),
var([valMaximumPointerValue], vbValue, 0),
CreateAtom(Baseclass, atmTemporaryLookupTable, [TemporaryLookupTable]),
{Determine the total number of atoms in the model}
ForAtomTreeUnder(
Model,
Do(
valNrOfAtomsinModel := valNrOfAtomsinModel + 1
)
),
{resize the temporary lookup table}
SetTable(valNrOfAtomsinModel, 2, atmTemporaryLookupTable),
{ Set old and new pointer values in the look-up table }
ForAtomTreeUnder(
Model,
Do(
valCounter := valCounter + 1,
SetCell(valCounter, 1, a, atmTemporaryLookupTable),
SetCell(valCounter, 2, att([ptrName], a), atmTemporaryLookupTable)
)
),
{ Sort column 2 (ascending) of the look-up table }
QuickSortTable(atmTemporaryLookupTable, 2, 1),
{ Determine minumum and maximum oldpointervalue in column 2 of look-up table }
valMinimumPointerValue := Cell(1, 2, atmTemporaryLookupTable, 1),
valMaximumPointerValue := Cell(valNrOfAtomsinModel, 2, atmTemporaryLookupTable, 1),
{ Loop over all atoms in Model and replace old pointer values with the new ones }
ForAtomTreeUnder(
Model,
Do(
atmTreeAtomBeingScanned:= a,
var([valNrOfAttributes], vbValue, 0),
var([valIndexFound], vbValue, 0),
var([valValueBeingScanned], vbValue, 0),
valNrOfAttributes := NrOfAttributes(atmTreeAtomBeingScanned),
{ Loop over attributes of current atom and replace old pointer values with the new ones }
For(
valCounter:= 1, valCounter <= valNrOfAttributes,
Inc(valCounter),
Do(
valValueBeingScanned := att(valCounter, atmTreeAtomBeingScanned),
If(
And(
valValueBeingScanned >= valMinimumPointerValue,
valValueBeingScanned <= valMaximumPointerValue
),
Do(
{ In case old pointer value within range, apply binary search to find index }
valIndexFound := BinarySearch(atmTemporaryLookupTable, 2, valValueBeingScanned),
If(
valIndexFound <> 0,
Do(
{ Replace old pointer value with new }
SetAtt(valCounter, Cell(valIndexFound, 1, atmTemporaryLookupTable), atmTreeAtomBeingScanned)
)
)
)
)
)
)
)
)
)
Well, that’s about it. I hope this thread will help you with the concept of pointer references in ED.