Proper way to set up an Array of Class Objects?

  1. 5 months ago

    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.

  2. Kem T

    Jul 23 Pre-Release Testers, Xojo Pro, XDC Speakers New York

    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.

  3. 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.

  4. Tim H

    Jul 23 Pre-Release Testers Portland, OR USA

    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
  5. 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?

  6. Kem T

    Jul 24 Pre-Release Testers, Xojo Pro, XDC Speakers New York

    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.

  7. 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.

  8. Kem T

    Jul 24 Pre-Release Testers, Xojo Pro, XDC Speakers New York

    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.

  9. Tim H

    Jul 24 Pre-Release Testers Portland, OR USA
    Edited 5 months ago

    @Gregory M I expected an array of class objects would be something like this

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

    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
  10. 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?

  11. Kem T

    Jul 26 Pre-Release Testers, Xojo Pro, XDC Speakers New York

    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.

  12. Kem T

    Jul 26 Pre-Release Testers, Xojo Pro, XDC Speakers New York

    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
  13. Tim H

    Jul 26 Pre-Release Testers Portland, OR USA

    @Gregory M 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?

    Correct.

    @Gregory M which way is preferable?

    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.

  14. last week

    Thomas H

    Dec 4 Stuttgart, Germany

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

  15. Tim J

    Dec 4 Pre-Release Testers, Xojo Pro Dehydrating in AZ

    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.

  16. Kem T

    Dec 4 Pre-Release Testers, Xojo Pro, XDC Speakers New York

    @Tim J I've now read that three times and still don't know what you mean. :/

  17. Tim J

    Dec 5 Pre-Release Testers, Xojo Pro Dehydrating in AZ

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

  18. Bob K

    Dec 5 Pre-Release Testers, Xojo Pro Kansas City

    @Tim J ReDim MyExamples(-1)
    For x = 0 To NumExamplesNeeded
    Dim thisExample As New Example
    ThisExample.Member = value
    ...
    MyExamples.Append thisExample.Clone
    Next

    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.

  19. Tim J

    Dec 5 Pre-Release Testers, Xojo Pro Dehydrating in AZ

    @Bob K 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 :P

or Sign Up to reply!