Confusion about Class Constructor timing

Xojo version current. Using Mac OS
I am creating a single instance of a class via a constructor
I am confused about when I see that instance change from it property of Nil to its name.

I have a class called GrammWNotesCL and its instance is created at this line

GrmInst = New GrammWNotesCL

This calls the constructor, which has only one line, which runs a method which basically fills an array.
I would think that by declaring New, the instance would change from Nil to GrmInst, but it isn’t. It is still Nil.
Has that timing changed or something?
Does the instance now become only after the constructor is finished?

Not sure what you mean by this.

By thus declaring new, GrmInst changes from whatever it was before (may have been Nil), to point at the new instance of GrammWNotesCL that was just created.

It is, unless an error occurs.
After that line GrmInst should be non-null.

if you are inspecting it during the constructor, it’s difficult to know when exactly the debugger would show that the object was non-null, (probably after it calls super.constructor) but surely it is unimportant.

You are calling super.constructor before you populate the array, arent you?

Suppose there isn’t a super?

Unless your constructor code is referencing GrmInst (which would be a very bad idea), why does it matter? But I would expect GrmInst to remain unchanged until after the constructor is complete.

The reason I am confused is i used to be able to assign stuff to properties of the class during this method, the one in the constructor.
These properties are Nil because the class is still Nil.
What else can I do?

How are you doing that? Show the code in the method that’s inside the constructor.

A new instance of a Class is not nil inside it’s own Constructor. However object properties of the class will default to Nil until they are initialized, and if this class has a superclass, that won’t happen until you call Super.Constructor.

I think we need more details here to be helpful.

I am going with Tim’s ideas. I think I have gotten away with something for a long time.

I changed my code and that problem disappeared.

It works the same as every other compiled object oriented language I have come across.

GrmInst, is a human readable label on a memory address. Until it is initialised GrmInst contains $0000 (nil)

New, calls the constructor function.

=, tells the compiler to assign the value returned from the function.

What is not entirely obvious is that an object is just a fancy structure and at runtime the constructor allocates space for the structure from the ‘heap’ of dynamic memory and returns the location implicitly.

So GrmInst is assigned the address of a new GrammWNotesCL object in memory (an instance) when the constructor returns.

You haven’t told us what you changed, neither have you (as requested) posted the code you originally had in that method, which would allow us to understand your confusion and explain things. Making random changes so that as if by magic things suddenly work, is not hlping us help you, neither does it mean you’ve actually learned from the exchange.

But this works as you said, you can set property values at the constructor time…


Apologies. I have a lousy memory, and forgot to explain myself.

The only thing I did was eliminate the method in the constructor, and added it after the instantiation, because the method would assign values to the class, which may or may not exist if called in the constructor.

Unfortunately as Tim H stated my class could remain unchanged until after the constructor, which means it could remain Nil and I couldn’t assign anything.

Then there’s something else the matter. One of the purposes of a Constructor, ISTM, is to initialise for example properties of the class. For instance, I subclass the SSLSocket, and the first thing I do in my Constructor is to invoke the SuperConstructor. After that I’m busy initialising properties of the SSLSocket as well as my own added properties. If one couldn’t do that, what would be the point?

I have another class which is not a subclass of anything and so I don’t call super.Constructor, as there is no super. All the Constructor does is initialise properties of my class:

me.bias       = if  (app.spambias=0, False, True)                // We'll use a bias
me.maxtoks    = 27
me.mindelta   = 0.0
me.perffactor = 1.0                                              // Set performance factor to 1.0
me.tkflag     = False                                            // Flag for collecting token and other data

This all works. There is no question of the instance not existing when the Constructor is called. This is why seeing your actual Constructor code and that of the method, is important.

Here is my constructor


Here is the code in the method. It Should all be part GrmInst. It works fine, and because of that I don’t think I need to answer questions, like what does this variable do.

//Return False = Good; True = Problems
//Var Zcnt As  Integer //Num of Fields, Zcnt = MnStuff.GrXCnt & the HList data
//Sets GrmUbnd to be used in place of calling LastIndex
//Called in App.OpenPrefs and PrefWindow.GrammListSave
//Line 0 of file:    hlist (Hierarchical); and //Line 0 of file:    hlist (Hierarchical)
//total  # of column (LastIndex) for row 1 in display has the # for MnStuff.GrXCnt
//Has headings by default as numbers
Var wholeFile(-1), test, zTest() As  String //, oneCell, ztest is for the hlist and # of cols in display//, rowFromFile
Var i, j As Integer//j is for rows or y direction; i is for columns or x direction

If App.ExstsTruu(MnStuff.GrmFileName) Then
  GrmWrdLstWhlF = App.StrpEncode(MnStuff.GrmFileName, "Grammar", False )
  If GrmWrdLstWhlF.IsEmpty Then
    #If TargetWindows Then
      bmsg = New BoxMssage( 0, "The " + MnStuff.GrmFileName.Name + " Is an Empty File.", MnStuff.GrmFileName.Name, CurrentMethodName )
      MessageBox("The " + MnStuff.GrmFileName.Name + " Is an Empty File.")
    MnStuff.GrmFileName = Nil
  End If
End If

If GrmWrdLstWhlF.IsEmpty = False Then
  If TargetWindows And GrmWrdLstWhlF.IndexOf(String.ChrByte(10)) > -1 And GrmWrdLstWhlF.IndexOf(String.ChrByte(13)+String.ChrByte(10)) = -1 Then
    bmsg = New BoxMssage( 1, "Do You Want to Convert this to Windows OS Format?", "Replace Line Endings", 4, CurrentMethodName )
    If LilW.LilBoxResp = 1 Then GrmWrdLstWhlF = GrmWrdLstWhlF.ReplaceLineEndings(EOL)
    LilW.LilBoxResp = 0
  ElseIf ( TargetLinux Or TargetMacOS ) And GrmWrdLstWhlF.IndexOf(String.ChrByte(13)+String.ChrByte(10)) > -1 Then
    If 6 = App.MyMsgBx( "Do You Want to View the Dictionary Re-Building Log?", False ) Then GrmWrdLstWhlF = GrmWrdLstWhlF.ReplaceLineEndings(EndOfLine.UNIX)
  End If
  If -1 = GrmWrdLstWhlF.IndexOf(EOL) Then
    #If TargetWindows Then
      bmsg = New BoxMssage( 0, "There Are Problems With the Grammar File " + MnStuff.GrmFileName.Name, MnStuff.GrmFileName.Name, CurrentMethodName )
      MessageBox("There Are Problems With the Grammar File ")
    GrmWrdLstWhlF = ""
    MnStuff.GrmFileName = Nil
  End If
  wholeFile() = GrmWrdLstWhlF.Split(EOL)
  test = ConvertEncoding( "HLIST", Encdng )//the test is for 4 = InStr
  zTest() = wholeFile(0).Split(DSep)'ztest is for the hlist (Hierarchical)
  MnStuff.GrmFileName = Nil
End If

//testing for HLIST or hierarchical. Headings is next row determines number of columns (MnStuff.GrXCnt)
If zTest(0).BeginsWith(test) Then
  GrmWrdLstWhlF = GrmWrdLstWhlF.Middle(GrmWrdLstWhlF.IndexOf(EOL) + EOL.Length)
  GrmListIsHier = True
  wholeFile.RemoveAt 0//HLIST
ElseIf 3 <= zTest(0).IndexOf(test) Then
  GrmWrdLstWhlF = GrmWrdLstWhlF.Middle(GrmWrdLstWhlF.IndexOf(EOL) + EOL.Length)
  GrmListIsHier = False
  wholeFile.RemoveAt 0//HLIST
ElseIf -1 < zTest(0).IndexOf(test) Then
  GrmListIsHier = False
End If

//Redundant If zTest.LastIndex >= 1 Then GrmCol = Val(zTest(1))

i = wholeFile(0).CountFields(DSep) -1
MnStuff.GrXCnt = wholeFile(0).CountFields(DSep) -1
GLHeading = wholeFile(0).Split(DSep)
GLHdShort = String.FromArray( GLHeading, "  " )//This is used in the GrmLstBox first row and used for comparison
wholeFile.RemoveAt 0

If  GrmCol > MnStuff.GrXCnt Then//tests to see if there are less columns than even needed
  #If TargetWindows Then
    bmsg = New BoxMssage( 0, "There Are Not Enough Columns for the Column Selected & the Grammar File " + MnStuff.GrmFileName.Name +_
    EOL + "The FIRST Column Is Now the Set Column.", MnStuff.GrmFileName.Name, CurrentMethodName )
    MessageBox("There Are Not Enough Columns for the Column Selected & the Grammar File " + MnStuff.GrmFileName.Name +_
    EOL + "The FIRST Column Is Now the Set Column.")
  GrmCol = 0
End If

If wholeFile.LastIndex < 0 Then Return

//Loads the GrmWrdArray with RowGrmClass items
For j = 0 to wholeFile.LastIndex
  zTest() = WholeFile(j).Split(DSep)// rowFromFile = WholeFile(j).NthField( DSep, i+1 )
  If zTest.LastIndex <> MnStuff.GrXCnt Then zTest.ResizeTo(MnStuff.GrXCnt)
  If zTest(i).IsEmpty = False Then
    Var xrow As New RowGrmClass (MnStuff.GrXCnt)
    Var srow As New RowGrmClass (0) = j = j
    xrow.dagta = WholeFile(j).Split(DSep)//rowFromFile
    srow.dagta(0) = String.FromArray( xrow.dagta, "  " )
    GrmWrdArray.Add xrow
    GrmWrdShort.Add srow
    j = j-1
    Continue For j
  End If
  //Next //For i As Integer = 0 to  GrCnt
  If GrmListIsHier Then
    If WholeFile(j).NthField( DSep, MnStuff.GrXCnt+1 ) = "True" Then
      GrmWrdArray(j).isDirectory = True
      GrmWrdShort(j).isDirectory = True
      GrmWrdArray(j).isDirectory = False
      GrmWrdShort(j).isDirectory = False
    End If
    WholeFile(j) = WholeFile(j).NthField( DSep, MnStuff.GrXCnt+2)
    GrmWrdArray(j).parent = WholeFile(j).ToDouble
    GrmWrdShort(j).parent = WholeFile(j).ToDouble
  End If//If GrmListIsHier Then
  ChgdGrmLst = False
Next //For j As Integer = 0 to GrmWrdArray.LastIndex

because of that I don’t think I need to answer questions, like what does this variable do.

Oh. Ok then.

How about ‘where are these variables coming from’ , instead?
Do you pass them into the constructor?
It looks pretty dodgy accessing properties of the App object or global variables in the constructor of a class.

Yes. That’s what me is for.

I’m getting the feeling that you might’ve been trying to access a global property that would point to an instance of your class, but you were doing that from within the class constructor, which means the instance had not yet been set up.?

As others have pointed out, if so, this would be not be the object oriented way of doing this. The method that sets up your constructor should be using the me, or self keywords. (In Xojo, me and self mean the same thing, except for in a window where me refers to a control and self refers to the window. That’s kind of a weird thing about Xojo.)

The problem is quite simple. For some reason, in the past, my single instance of the was not Nil when the method was called. The cause - 2 different machines.

Maybe some internal mess based on timers instead an immediate queued run where it should belong or something like that. Maybe in some machines with some specific timer resolutions it fires at a “wrong” time, or some kind of interruption gets in between part_a() ended and part_b() that comes fired by a timer later, as some another event.

When I was introduced to Xojo years ago I was bitten by the way Xojo uses timers everywhere and some out of order events due to it.

Also, when you instantiate an object, I do expected:

o.Create() // internal. It gets allocated
o.Init() // Internal. Necessary internal steps to set it up are done, as setting some default values
o.Constructor() // pass the object to user control so they can customize things as necessary
… // Go. It’s ready. Do whatever you want with the object.

And Xojo destroyed some values set with an additional step fired by “Inspector Behavior” AFTER the constructor and I was expecting to be done at the Init() step and receiving it ready to be used at the Constructor() time.