Proper way to set up an Array of Class Objects?

Can anyone tell me why my class array has 10 items all identical to customer(10)?

dim TempCust as new classCustomer
dim i as integer

for i = 0 to 9
TempCust.name = “ABC” + i.totext
TempCust.Rate = i*101 + 0.357
TempCust.Active = true

Customers(i) = TempCust
next

I dimensioned the array in the declaration to be 10 elements (Customers(9))
Alternatively, I dimensioned it to (-1) and then I put this in the loop
Customers(i).append( TempCust)
And got same result.

I also checked it in the debugger, and every append, caused every element to update to the latest one, so the debugger progression of customers was like
0
then 1, 1
then 2, 2, 2
then 3, 3, 3, 3
etc.

I have spent an hour looking at the programming guide, the forum, and sample projects, and can not get this simple thing to work.

You’ve only created one instance of your class and assigned it to your array ten times. Move the Dim statement into the loop instead so a new instance is created before it’s assigned.

I tried this but got compiler error :

for i = 0 to 9
TempCust.name = “mem” + i.ToText
TempCust.value = i * 10.1 + 0.357
TempCust.locked = false

dim Customerss(i) as new classCustomer
Customerss(i) = TempCust
next

In the two ways I did it before, it did create all 10 objects in the array - but they were all equal to the last one.

Kem meant the other dim statement.

dim i as integer

for i = 0 to 9
   dim TempCust as new classCustomer   // this creates a new object each time
   TempCust.name  = "ABC" + i.totext
   TempCust.Rate = i*101 + 0.357
   TempCust.Active = true

   Customers(i) = TempCust 
next

Ok thank you. I would have expected this to be an error - because it looks like you are dimensioning the same thing over and over again. For example, this would not fly :

dim i as integer
dim i as integer
dim i as integer

so this line : " Customers(i) = TempCust "

is apparently different than “j = i” which send the value of i to j, but there are two different memory locations for i and j.

So does “Customers(i) = TempCust” seems more equivalent to equating the two items as clones with the same memory location, is that right?

Xojo respects scope so a variable dim’d within a method is only valid within that method, and one dim’d within a block (if, while, do, etc.) is only valid within that block.

“Clones” is the wrong term as it implies more than one object, but I think you’re on the right track. Internally, every variable holds an address to some thing, whether than thing is a string or an object, so assigning the value of var1 to var2 is setting up two variables that both hold the same address, i.e., there is still just one thing. For objects, you have to call “New” each time you want another one.

BTW, in the future, please use the Code tags to format your code and help us help you.

Thank you.

  1. What do you mean by “Code tags”? I don’t understand what that means.

  2. I expected an array of class objects would be something like this

    For i = 0 to n
    Customers(i) = new CustomerClass
    Next

or else if n are already defined, then to append another one :

 redim (Customers (Ubound)) as new CustomerClass

The main thing I am looking for is a single good example of how to make an array of class objects, where the number of array elements might vary. From looking at the documentation and example projects, I have not been able to find that.

PS - when I come back to these forum threads, it says I don’t have permission to give a response - so I have to copy my response, reload the page, then paste it and it works.

If you look at the toolbar as you type the message, there are a number of icons. One is labelled “Code” when you point at it and it will insert for you tags that will mark the text as code. For an example of what that looks like, see Tim’s post above.

Here is some example code:

dim custArr() as CustomerClass

for index as integer = 0 to someArbitraryLimit
  dim c as new CustomerClass
  c.Prop1 = value1
  c.Prop2 = value2
  // etc.
  
  custArr.Append c
next

On every iteration of the loop, this creates a new CustomerClass instance, fills in its properties, then appends it to the array.

[quote=397667:@Gregory Moore]I expected an array of class objects would be something like this

For i = 0 to n
   Customers(i) = new CustomerClass
Next

[/quote]
You are correct. Your original code just wasn’t doing this. It’s a very common mistake. There is a subtle difference between

dim c as CustomerClass

c = new CustomerClass
for i = 0 to n
   Customers(i) = c
next

and

dim c as CustomerClass

for i = 0 to n
   c = New CustomerClass
   Customers(i) = c
next

The first will create a single instance of CustomerClass and append it to all the elements of the Customers array. The second creates a new instance of CustomerClass for each element of the Customers array.

As for Dim, that’s a matter of Scope. If you Dim a variable inside a block of code (IF, WHILE, FOR all define a block) then it exists only within that block. Ie.,

for i = 0 to n
   dim c as CustomerClass  // c is created anew each time
   c = new CustomerClass
    ...
next  // c is destroyed here
// c doesn't exist here

I personally prefer to dim the variable outside the block and only use NEW within the block

dim c as CustomerClass
for i = 0 to n
   c = new CustomerClass
   ...
next

I never realized that Xojo was sensitive to Begin-End blocks. I assumed anything defined in a method was existent and available from the declaration until the end of the method. So thats a revelation, and contrary my prior programming experience.

But if you define an array of class objects outside in a module (as a global)
Customers(-1) as CustomerClass

Then, later within a method, you redim it or append it (which way is preferable?) ? And then I assume it makes that global with the new size?

In the example you cited, “I assume it makes that global with the new size” sounds like you think you’re dealing with different things. You’re not, there is only one array no matter how many ways you refer to it.

Example:

Module1
  Global Arr() As String

Sub SomeMethod()
  Arr.Append "A"
  dim arr2() as string = Arr // Still just one array
  redim arr2( 9 )
  arr2( 9 ) = "B"
  MsgBox Arr( 9 ) // "B"
End Sub

As for whether to use Redim or Append, it depends entirely on what you’re doing. If you know how many elements you need, you can use either. If you don’t, you must use Append. But do not under any circumstances Redim within a loop unless you despise your users.

BTW, you can create a new variable in in a method that has the same name as one of a higher scope. For example:

Property
  MyProp As String = "Hey"

Sub MyMethod()
  dim myProp as string = "Ho"
End Sub

Sub Printer()
  MyMethod
  MsgBox MyProp // Hey
End Sub

[quote=397939:@Gregory Moore]But if you define an array of class objects outside in a module (as a global)
Customers(-1) as CustomerClass

Then, later within a method, you redim it or append it (which way is preferable?) ? And then I assume it makes that global with the new size?[/quote]
Correct.[quote=397939:@Gregory Moore]which way is preferable?[/quote]
If you know the number of elements you need, and if that number is sufficiently large, you get a little better performance out of a single Redim, followed by a loop that sets the values. Otherwise, use Append.

… a little objection: found this channel while searching for similar problem…
This helped me a lot. Thank you all!

Hmm, interesting. I’ve always added a “Clone” method that copied the members of the class to a new instance of the class each time through the loop based on arrays of classes discussions from back in the RB 4 days on the NUG.

ReDim MyExamples(-1) For x = 0 To NumExamplesNeeded Dim thisExample As New Example ThisExample.Member = value ... MyExamples.Append thisExample.Clone Next
The Clone method then creates a new instance of the class that is returned as a new instance and appended to the global (in my case) array of the class.

If I’m reading this correctly, the assignment of the inner loop copy of the temporary class is assigned to the permanent real copy retains that temporary copy to the permanent array with that mechanism. And, even though the inner loop data has gone out of scope, the now appended address of the temporary class to the permanent class sticks around because of the assignment.

While more of a curiosity, does anyone who was around back then remember WHY we discussed this beyond scope rules and came up with the Clone process? I used to have the NUG archived locally, but finally cleared the space last year.

@Tim Jones I’ve now read that three times and still don’t know what you mean. :confused:

It simply means that I’m doing far more work than required to achieve the required result based on poorly aging ideas :smiley: .

[quote=416728:@Tim Jones]ReDim MyExamples(-1)
For x = 0 To NumExamplesNeeded
Dim thisExample As New Example
ThisExample.Member = value

MyExamples.Append thisExample.Clone
Next[/quote]

This seems like redundant code (unless I’m missing something). Presumably your clone method creates a new instance of my MyExample? Therefore you create a new MyExample and then clone it. I think you could get by with just the New and be done with it and add it to the array.

That was my point. Luckily, I only use this type of code-overkill at array initialization, so the overhead is not noticeable. However, it will be “not there” by the end of the day :stuck_out_tongue: