Array of Objects Inside Another Object!


capstone

Recommended Posts

So I have this other question about objects. I have an object called Location and I'm trying to create another object called AlgBlock inside it.

1. I have the definition of class AlgBlock outside of Class Location, is that okay?

2. I'm trying to have an array of AlgBlocks inside Location and it's not working. I can only get the first element to display it's value.

Here are my class difinitions:
*****************************************
//Initialize Variables
class AlgBlock
   //A class to hold the Algorithm settings.  
   Global Alg_Empty = 0 //Empty
   local num_conditions = 0
   local string strCType = {"None", "None", "None"} //Condition Type (Threshold, On/off)
   local CSource = {0,0,0} //Source ADC/Relay number
   local string strCGreater  = {"=", "=", "="} //Condition Greater
   local CValue = {0,0,0}  //Condition Value
   local num_results = 0
   local string strRAction = {"None", "None", "None"} //Resulted Action (Set, Clear)
   local RDestination = {0,0,0}	//Destination Relay number 
   function OnCreate()
	  ? "Alg_Empty = 0"
	  Alg_Empty = 0
   endfunction
endclass

class Location
   local ID = 0
   local string phone_number = "None" 
   local string name = "None"
   local Refresh_Time = 0
   local Active = 0
   local ADC [8] = 0 //Array of ADC values - (0-7:Pressure sensors)
   local Relay [8] = 0//Array of relay values - Total of 10 Relays.(0-3:12V, 4-7:AC, 8:12V,9:AC)
   local UVT[8] = 0
   //***** Algorithm Block Variables:
   Global current_Alg = new(AlgBlock)
   Global Alg = current_Alg
   function OnCreate()
	  ? "Creating New alg block.
	  Alg[1] = new(AlgBlock)
	  Alg[1].Alg_Empty = 1
   endfunction
endclass

Global current_location = new(Location) 
Global All_loc[0] = current_location
**************************************

So when I "watch" All_loc[0].Alg[1].Alg_Empty, I get "Invalid object reference," while All_loc[0].Alg[0].Alg_Empty gives me "0".

2. Why is that?

Thanks a bunch!

Link to comment
Share on other sites

First, you shouldn't really put global declarations in the class definition.

Second, see your other post concerning declaring array variables and initializing them in one.

And finally to answer the question at hand: this is actually one of the little things that kept us from really releasing DF OOP, the other two being inability to use the debugger and step through script and error messages giving line numbers from the beginning of member functions. All of these are easily worked around though, but we just didn't think it worthy of a full release. However, at this rate, with all the posts about classes, we might as well release it.

Anyhow, I wander. The issue is that you can't have two sets of [] subsetting in a single entry. The way around this is to put All_loc[0] into another variable and then watch it instead. Remember doing x=y[0] simply makes x refer to y[0]. So:

global cur_all_loc = all_loc[0]

? cur_all_loc.alg[0].alg_empty

I should add that this reference assignment makes it real handy to do all sorts of things with objects. For example, if you had an array of objects, each containing a set of parameters and you had a screen to display the parameters for one of the these objects, you could have the screen pull values from a single variable, like my cur_all_loc, and then simply assign cur_all_loc to the particular array element you want to look at.

Link to comment
Share on other sites

Well, first off, when I used local instead of Global, it wouldn't compile. It gave me this error message:

C1000 Channel or function not found - Error compiling sequence Auto_Startup, Line Number 43

But when I changed that to Global it would compile fine. Just now I tried fixing this issue this way:

   local current_Alg = new(AlgBlock)
   local Alg 
   Alg = current_Alg

Instead of doing both steps at once and it worked.

Secondly, I did try doing this function as you said:

function OnCreate()
	  ? "Creating New alg block.
	  Alg[1] = new(AlgBlock)
	  private ob = Alg[1]
	  ob.Alg_Empty = 1
endfunction

But it didn't fix the problem. The problem is, when I executed:

Global ob = All_loc[1]
? doubletostr(ob.Alg[1].Alg_Empty)

And I get the same error: Invalid object reference

Please help!!!

Link to comment
Share on other sites

OK, first, putting stuff other than local declarations and member functions inside a class declaration will have unpredicatable results. Also, you can't (ok, don't want to) do new() inside a local variable declaration. If you do, what you end up with is all instantiated objects referencing the same object. What DF does internally when you do a class declaration is create an object internally including doing all the variable declarations and assignments done in the declarations. This means that that internal object would have an instantiated instance of Alg_Block. Well, when you then instantiate this object, it simply copies all the local variables from the internal one it created from the class declaration to the one you just instantiated. The thing is, variable copying for variables with references to objects simply copy the reference, not the object, so the newly instantiated object just gets a reference to the internal one.

Wow, that was a long winded explanation. Bottom line is that local variable declarations only get executed once, not every time the object gets instantiated, so you only get one new(Alg_block).

On a side note: this is why you can change the class declaration member functions and any objects already instantiated for this class will pick up the member function changes (but not the variable initialization / declaration since this is a copy).

You should instead instantiate objects to be stored in local variables in OnCreate().

In your on create:

function OnCreate()
	  ? "Creating New alg block.
	  Alg[1] = new(AlgBlock)
	  private ob = Alg[1]
	  ob.Alg_Empty = 1
endfunction

there is no reason to put alg[1] into a private. You are only subsetting once, so you can jsut do:

alg[1].alg_empty = 1

As for the problem at the end:

Global ob = All_loc[1]

? doubletostr(ob.Alg[1].Alg_Empty)

I'm willing to bet that all_loc[1] doesn't contain an object. Did you instantiate it somewhere? Try doing

? all_loc[1]

Link to comment
Share on other sites

Thanks for the explanation. And now I'm confused a little, but I tried the two different ways that I'll explain below and I didn't get the Alg, i>0 to work. Only my Alg[0] works.

Confusion: When you say "You should instead instantiate objects to be stored in local variables in OnCreate()." what do you mean?

Do you mean I should first declare "local current_Alg " and then in OnCreate() instantiate the new() object to it like this?

class Location
   ....
  local current_Alg = 0
  local Alg
   function OnCreate()
	  current_Alg = new(AlgBlock)
	  for (private i = 0, i < MAX_ALGBLOCKS, i++)
		 Alg[i]= new(AlgBlock)
	  endfor
	  Alg[0] = current_Alg
   endfunction
endclass

Or should I declare the local inside the function like this?:

class Location
   ....
   function OnCreate()
	  local current_Alg = new(AlgBlock)
	  for (private i = 0, i < MAX_ALGBLOCKS, i++)
		 local Alg[i]= new(AlgBlock)
	  endfor
	  Alg[0] = current_Alg
   endfunction
endclass

I need to access Alg from outside, so I need to be able to assign something like this:

All_loc[0].Alg[2].CSource[1] = 2

At this point, I can do this:

All_loc[0].Alg[0].CSource[1] = 2 and it works, but when Alg, i>0, it doesn't work! :( I'm using the same method though to declare Alg[0] and Alg, so I don't see why this happens.

And to answer your "bet" question, this is what I get when I type ? all_loc[1]:

"Object(s)"

I am indeed instantiating All_loc[1] in another sequence. But All_loc[1].Alg[1] returns nothing! (All_loc[1].Alg[0] returns "Object(s)"!)

Even though it's instantiated, since I have some printing code that shows it instantiates the object (in my for loop, I have it print the i each time and in my AlgBlock's OnCreate function I have it print out the Alg_empty each time, so I can see the number of times it gets created), but later I can't seem to access other elements than 0 or they go away somehow!

Thanks!

Just for reference:

class AlgBlock
   local Alg_Empty = 0 //Empty
   local num_conditions = 0
   local string strCType = {"None", "None", "None"} //Condition Type (Threshold, On/off)
   local CSource = {0,0,0} //Source ADC/Relay number
   local string strCGreater  = {"=", "=", "="} //Condition Greater
   local CValue = {0,0,0}  //Condition Value
   local num_results = 0
   local string strRAction = {"None", "None", "None"} //Resulted Action (Set, Clear)
   local RDestination = {0,0,0}	//Destination Relay number 
   function OnCreate()
	  ? "Alg_Empty"
	endfunction
endclass

Link to comment
Share on other sites

1) you can only declare local's inside class references, but outside member functions

2) you should never initialize a local with an object during declaration for reasons I explained before, so yes, you should do it like you showed in OnCreate, except that you are instantiating an extra object. You instantiate one and put it in current_Alg, then you instantiate one in alg[0] in the for loop, then you reassign alg[0] to the one in current_Alg, thus destroying the one you just instantiated in the loop.

3) As I said originally: you cannot have two []'s when trying to access members (unless working with 2 and 3d arrays, but that's different), so All_loc[0].Alg[2].CSource[1] won't work because there are three []. You have to assign all_loc[0] to a temporary variable, then assign tempVar.alg[2] to another temp, and then you can retrieve CSource[1]:

private tempAllLoc = all_loc[0]

private tempAlg = tempAllLoc.alg[2]

return(tempAlg.CSource[1])

See how in each statement there is only one [].

Link to comment
Share on other sites

Here is what I have, I made the corrections you said:

class Location
   local current_Alg 
   local Alg
   function OnCreate()
	  ? "Creating New alg block."
	  //current_Alg = new(AlgBlock)
	  ? "MAX_ALGBLOCKS: " + doubletostr(MAX_ALGBLOCKS)
	  for (private i = 0, i < MAX_ALGBLOCKS, i++)
		 ? doubletostr(i)
		 Alg[i]= new(AlgBlock)
	  endfor
	  current_Alg = Alg[0]
   endfunction
endclass

And when I execute these lines, this is what I get!

global tempAllLoc = all_loc[0]

global tempAlg = tempAllLoc.alg[2]

global temp = tempAlg.CSource[1]

C1000 Channel or function not found: Line 1

It doesn't like the third line! It can't find Alg[2]! why?

Link to comment
Share on other sites

Looks like there are problems calling OnCreate(). They have been fixed and will be in the next, 5.85 release (coming shortly). What happens is that OnCreate() is getting called in the wrong scope, so it executes, but it sets locals incorrectly.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.