Odd NilObjectException

I have an odd NilObjectException, too. The NOE occurs when I’m getting mailboxes from Mail while Mail has no account. I can reproduce the behaviour on another user. But I wasn’t able to get codesign working on the user. The app only hangs in this case. Instead I added some logging.

Below is part of the logging when getting the mailboxes doesn’t have a result but there is no NOE:

2023-09-28 12:47:27 CCEmailView.TGetMailboxes.Run accountname: Mail
2023-09-28 12:47:27 CCEmailView.TGetMailboxes.Run 1
2023-09-28 12:47:27 CCEmailView.TGetMailboxes.Run 2
2023-09-28 12:47:27 GetImapStatus.Constructor
2023-09-28 12:47:28 GetImapStatusMail.getAllAccounts accounts:
2023-09-28 12:47:28 GetImapStatusMail.getAccounts no accounts found
2023-09-28 12:47:28 GetImapStatus.Constructor done
2023-09-28 12:47:28 CCEmailView.TGetMailboxes.Run 2a
2023-09-28 12:47:28 CCEmailView.TGetMailboxes.Run 2b

When trying again I get the following in the log:

2023-09-28 12:47:33 CCEmailView.TGetMailboxes.Run accountname: Mail
2023-09-28 12:47:33 CCEmailView.TGetMailboxes.Run 1
2023-09-28 12:47:33 CCEmailView.TGetMailboxes.Run 2
2023-09-28 12:47:33 --------------------------
2023-09-28 12:47:33 An error happened:
2023-09-28 12:47:33 Class/Method: CCEmailView.TGetMailboxes.Run
2023-09-28 12:47:33 Time: 28. Sep 2023 12:47:33 60903313
2023-09-28 12:47:33 Type of Error: NilObjectException
2023-09-28 12:47:33 Error Number: 0
2023-09-28 12:47:33 Error Message:
2023-09-28 12:47:33 --------------------------
2023-09-28 12:47:33 Stack:
2023-09-28 12:47:33
Sub CCEmailView.CCEmailView.TGetMailboxes_Run(CCEmailView.CCEmailView, Thread)

So the NOE happens between “TGetMailboxes.Run 2” and “GetImapStatus.Constructor”.

'extra logging
Globals.theErrorLog.logitem(currentMethodName + " 2")

'get mailboxes from IMAP or email client
dim loadForeignData as Boolean

Redim ImapStatus(-1)
dim MailboxDictionary as new Dictionary
if loadForeignData then
 'some code for testing
else
  
  dim theMailboxGetter as getAllMailfolders
  if not isIMAP then
      
      dim theGetter as new GetImapStatus(BundleID)
      'extra logging
      Globals.theErrorLog.logitem(currentMethodName + " 2a")
      ImapStatus = theGetter.getAccounts
      'extra logging
      Globals.theErrorLog.logitem(currentMethodName + " 2b")

Which line of code between 2 and 2a could make an NOE?

1 Like

Or

So maybe inside loadForeignData? Or something in theGetter ?

Could it be inside of this constructor? Since you don’t see that one in the log with exeption?

1 Like

LoadForeignData is a special test mode for debug mode only. The first line of GetImapStatus.Constructor is logged, too:

Globals.theErrorLog.logitem currentMethodName, "open"

Where is this in the log?

The line is in the first log where everything works. The line is missing when I get the NOE.

So there could be something Nil in there?

1 Like

Can you use remote debugger to step through the code? It can be difficult to set this up, but ultimately worth the time spent.

1 Like

Good idea!

have you try catch in this constructor? GetImapStatus
or what is the code in there?

log the beginning and end of each method.

use a variable “now i will do this”
and if you catch an error you can output or log this variable too. similar to row numbers.
add conditional compilings for bug hunting.

1 Like

Argh…

Remote debugging turned out to be easy to set up. The NilObjectException comes from

Redim ImapStatus(-1)

Makes me feel really stupid.

1 Like

How does Redim() cause a NOE? is there a destructor?

1 Like

ImapStatus is a string array for holding information of accounts from an email client. I’m setting it in this line:

ImapStatus = theGetter.getAccounts

When the email client doesn’t have accounts then ImapStatus becomes nil. Unfortunately, arrays are treated something between an object and a simple value.

And, of course, all my email clients have accounts so this never happens for me.

1 Like

I asked Norman because I was really confused too. Apparently this can happen when you don’t return an array from a function and use a variable to capture the result of the function.

Norman filed a ticket to make this behavior more logical after our discussion: #74264 - functions that return arrays need to return an empty array of the right type by default NOT NIL !

There is a sample project on the ticket that you can play with to see the behavior for yourself.

2 Likes

Can you post sample code of ‘theGetter.getAccounts’?

If there are accounts you return an array with the accounts, right? if there are no accounts, you don’t return an empty array?

I just want to understand how ‘theGetter.getAccounts’ assigns a Nil here. Thanks.

I remember some years ago, perhaps 10 years, when this case was even worse. At that time, you couldn’t compare an array against nil (the compiler would complain the types didn’t match). There was no obvious way to check if the method correctly returned something other than handling a NilObjectException by trying to access the “array”.
Things have progressed :slightly_smiling_face:

If it’s really a Xojo WTF (dangerous foot-gun) maybe post it to the https://forum.xojo.com/t/xojo-wtf thread?

This seems like logical and expected behavior to me.

1 Like

It’s a strongly typed language. I defined the return type as an array of data type. I would expect an empty array, not a nil object. Hence the ticket Norman created.

1 Like

If you have a function

MyFunction() as MyClass

and fail to return an instance of MyClass, the function returns Nil. The behavior of a function that returns an array seems consistent with that.

If a function returns a primitive and you don’t return a value, you get the default value for the return type, but arrays are not a data type have no default “value”, so Nil make more sense to me.

2 Likes