MAJOR BUG in R2 that needs a fix asap

I don’t see any change. When f.child(“test”) exists then child(“thisisafile.txt”) will return a non-nil FolderItem and you can check whether the file exists (and create it if it doesn’t). If on the other hand f.child(“test”) does not exist then Child(“thisisafile.txt”) will return nil as it isn’t a valid FolderItem. But that’s just how it always has been. R2 hasn’t changed anything in this respect.

For this reason I always check for a FolderItem being nil before doing anything else with it. And I have written a method EnsureFolderExists, years ago, that will create an entire hierarchy of subfolders if necessary. In this case I would call EnsureFolderExists to make sure there is a “test” folder before creating a FolderItem for its child (that may or may not exist but the FolderItem is guaranteed to be non-nil).

Yes, I understand that it is consistent now, but it will break code for sure for many people who used .exists

Seems right.

If the folderitem is nil, then it is an invalid path and you cannot create a file or folder using it.

If it is not nil, then it may or may not exist, and thats the time to check .exists

I don’t think I have ever used .exists without prefixing with <> nil

In the case of

SpecialFolder.Desktop.Child(“thisDoesNotExist”).Child(“thisAlsoDoesNotExist”)

You absolutely shouldn’t expect to be able to just create the child - it would fail.

So in older versions, the creation would fail and you probably wouldnt know why.

In the new, you can test whether the path is good enough to create, before you try, by checking for nil.

But what good is chaining a bunch of .Child together and then getting .Exists = False if you don’t know which part of the path is invalid?

If anything other than the last item doesn’t exist, then you won’t be able to create something at that path.

I suppose if you were using that technique just to check if a path existed at all, and you didn’t care about why, then it would break that code, but I think that fixing the bug/inconsistency is the correct move by Xojo.

3 Likes

This is irrelevant, because as explained above, if you chain this way and go past a non-existent folder you’ll likely crash with a NilObjectException before you have to worry about which part of the path exists.

Unfortunately you have to check each folder level going down when creating the subfolders eg.

dim f as FolderItem = SpecialFolder.ApplicationData
f = f.Child("MyApp")
If Not f.Exists Then f.CreateFolder
f = f.Child("FolderA")
If Not f.Exists Then f.CreateFolder
f = f.Child("FolderB")
If Not f.Exists Then f.CreateFolder

Exception err as IOException
// Handle cases where a folder can't be created for some reason

This is intentional by design so not a bug. If you really want to create a full valid path without having to write that out each time then you could make your own re-usable global method like CreatePathToFolderItem(path as String) as FolderItem which could step through a given path, creating missing folders as it goes before returning a final valid folderitem.

1 Like

I agree with you.

The bug before was that it apparently wouldn’t throw a NilObjectException and that has been fixed as it should.

I haven’t experienced that since my code is written similar to your example where every item is the path is validated.

I was replying to a post that was saying that this change would break existing code and I think that it should because that code is incorrect.

Behaving consistently between platforms is important, so something needed to change. The “right” change would have been to make Windows and Linux behave like the Mac, since it would disrupt less code and behave more predictably. I am assuming making them behave that way was not possible, so given the options, making Mac conform to Windows and Linux is the right call. It may be a dumb design, but consistent is better.

2 Likes

My view on the “Xojo ‘simple’ way of use design” would be, Child() should always return some FolderItem object for all platforms and such object set a lot a flags describing its state.

.Exists():

  • True only if a valid path and such path resolves to something that really exists
  • False otherwise

.ValidPath():

  • False for example for
    C:\whatever\l:\colon? // invalid
    C:\thisExists\notExists\notExists // Has intermediate non-existent subfolders
  • True for C:\thisExists or C:\thisExists\dontExistYet

Etc.

Nil should be only the last case, probably memory related where your system is completely unstable at such point.

A new .ChildOrNil() should be introduced for those wanting such Nil behavior for invalid childs.

That is where I go long time ago because I had enought to scratch my head with

ìf f.Nil Or Not f.Exists Then

when there is an error. So to get it simple, I split the line to two if Blocks:

ìf f.Nil Then
// do somthing
End If

If Not f.Exists Then
// do somthing
End If

PS: 40 years ago (or so) there were code one liner in basic challenge: I never understand the idea…

Write a line with as many as possible instructions…

I put that in the trash bin with Var f As FolderItem = SpecialFolder

I try to place one set of instructions per line (preceded with a meaningful comment line).

“But since we are all free, do what you please.”

Shouldn’t that read:

if f = nil or Not f.exists then
   // Do something
end if
2 Likes

This is how I do it, with nested folder analysis, starting at the first in the chain of folders.

If the app can’t create its own folder, then I offer the user a dialogue box for manual selection.

Then we need an explicit Docs page to cover the scenario being addressed in this thread, with code sample to show people how it needs to be handled.

Has someone created an Issue to address this particular source of frustration?

I don’t understand because it seems like some people are expecting Child to behave in some new way. The way that’s documented, the Child of an Exists=false, should be nil. I swear it always had been and if it suddenly isn’t that’s a regression.

Can someone explain what the complaint is?

I’m a little lost, because the only public ticket here is the one about the Constructor path not operating as it was documented and should have been. The change note from the private ticket suggests Child had some kind of regression that has been fixed.

I don’t see how either operating as documented would break code.

1 Like

OP expects these two cases to work:

Var f as Folderitem
f = SpecialFolder.Desktop

If f.child("doesNotExist").Exists = False Then
  Break
End

If f.child("doesNotExist").child("doesNotExist").Exists = False Then
  Break
End

they both work in Xojo2026r1.2 but the second now shows an Exception with 2026r2, so it will break OP’s code.

No you’ve got it right. Mac was behaving differently from the documentation, so that got fixed. My complaint is that the documented behavior is unintuitive. If you go back to my comment MAJOR BUG in R2 that needs a fix asap - #16 by Thom_McGrath I posted three lines that all use the same feature, but behaves in 3 different ways. The Mac behavior made more sense.

I don’t think there is a bug that needs to be fixed. It’s behaving as documented, so… fine.

I think your example makes perfect sense though and is how it should work.

Call SpecialFolder.Desktop.Child("thisDoesNotExist") // Non-nil FolderItem with Exists = False
Call SpecialFolder.Desktop.Child("thisDoesNotExist").Child("thisAlsoDoesNotExist") // Nil FolderItem
Call SpecialFolder.Desktop.Child("thisDoesNotExist").Child("thisAlsoDoesNotExist").Child("surprise!") // NilObjectException

The first one is non-nil so that you can use the FolderItem object to create it.
The second one is nil because .Child returns a nil object due to the parent not existing.
The third one throws an exception because you are trying to call a method on a nil object.

1 Like

And fix for that would be

It would allow such “desired” construct to work as

If Not f.child("doesNotExist").child("doesNotExist").Exists Then
  // there's nothing like that in that final path or the path is invalid
End

One current hack is

Var fExists As Boolean // Store the existence flag tested here

Try
  fExists = f.Child("doesNotExist").Child("doesNotExist").Exists
Catch NilObjectException
  fExists = False
End

Trust me, I understand why it behaves this way. I’m saying it shouldn’t behave this way. There is no good reason why Child should return nil when the parent does not exist. I’ve heard it called an invalid path, but there’s nothing invalid about it. Just like String.FromArray(Array("", "home", "user", "documents", "stuff"), "/") would give you a string to a valid path - as in it does not contain illegal characters and its length is not too long - there is no good reason why I shouldn’t be able to get a FolderItem to the same path regardless of its existence at any level.

As I’ve mentioned, my best guess is this behavior comes from the Windows system-level calls behaving this way, so the other platforms have to suffer accordingly. Lowest common denominator and all that. But if I’m wrong and this is a Xojo-imposed limitation… sheesh that was a bad one.

I should get an exception for this because the FolderItem is attempting to point to location that can not ever exist.

Var File As New FolderItem("You Cannot Use < In File Names On Windows.txt", FolderItem.PathTypes.Native)

I should not get an exception for this because the FolderItem is attempting to point to a location that can exist, but does not exist.

Var File As New FolderItem("C:\Users\User\Documents\My App Stuff\Settings.txt", FolderItem.PathTypes.Native)

That’s the logical behavior. But not the way it behaves.

Like I’ve said over and over, I understand the mechanics, and the fix was good in the sense that it makes the Mac behave as documented. I agree that they should be consistent. I disagree with the documented behavior.

1 Like