Computed properties nightmare

So yesterday, I had a complete nightmare situation.

Xojo was running slowly; I had been debugging, had multiple projects open and gone over my 16GB memory limit on my machine. So I quit Xojo (and a bunch of other application) and re-opened. Continued working on my code and then ran the project.

None of the controls on a container control would show.

In this project all the controls are custom canvases and are placed on a canvas which is placed in a NSScrollView class. I even added regular controls to the canvas, those wouldn’t display. I then added regular controls to the container control and they still wouldn’t show.

I made the scrollview invisible, and continued to strip down my control and remove all declares on the window, still nothing…

I’m using a lot of customized animation and while I know that my code for the animation has a limited, I even removed all animation from the controls.

Eventually I found the problem, it was a computed property had started firing before the open event, while there’s code in the scrollview to protect against this, it was still somehow corrupting the entire window.

It was only when I added a property to the continaerControl called “isOpen” and was set to true on the Open event of the window (with the computed properties simply bailing when it’s false), did I finally get somewhere. I added “System.debuglog” functions all over the place, and that’s how I figured it out.

We’re talking about 7 hours it took for me to figure this out, I was very very frustrated during the entire process.

As far I can see, there should be only one reason as to why Xojo should fire a computed property (on a control), and it should occur after the Open event.
#1 The property is available in the inspector.

Otherwise it should not fire until it’s called within code that we write.

This has tripped many people up and debated as many times. Xojo seems pretty settled on this behavior, it goes…

Regular Properties initialized
Constructor
Computed Properties initialized
Open Event

I use method pairs instead of Computed Properties so I don’t have to worry about initialization.

Looks like I’ll be doing this too, which is a shame, I love computed properties, I wouldn’t mind so much if it did this from the moment I created the computer property, but the fact that it only started doing this once Xojo was restarted, really made it difficult to track down.

That’s a bug I’ve tried to point out but never got traction. Maybe there’s a feedback for it now though. Computed Properties that you add after placing an instance don’t get initialized… until you save and reopen the project.

I bumped into that several times with niceties such as NOE.

I finally use a flag that I set in Open to know when code in get can actually run.

or make a new event “PostOpen” that you fire at the end of open

Just out of curiosity… if they didn’t fire before the open event, how would you use them for user exposed properties? It’s a double edged sword where we’ve erred on the side which allows you to correct for it.

FWIW, changing this behavior could break countless projects, including a large portion of the web framework, so I find it unlikely that it will.

It’s a classic chicken-egg dilemma. Thanks for clarifying the reasons, Greg!
Well, I do love computed properties in my projects and don’t want to miss them. They make debugging so much easier.

One way to fix it is of course to add a hasInitialized Boolean to your class and, while it is false, have all setters write into buffer properties. Then in the open event set hasInitialized to True and run your own initializers, copying the temporary buffer properties into their real places.

Another option that works well with custom controls is to make the object itself a computed property – like in the case of a view subclass that will become the object when you replace or add it to the canvas wrapper. When a computed property wants to write to the object (and it does not exist), the creation routine is run and the view is buffered. Every concurrent setter writes directly into it. This saves you from installing buffer properties, and in the open event you simply do the visual initialization (give the object its frame size and replace or add it to the canvas view).

I understand the dilemma and agree with Xojos solution, especially now that code relies on the behavior. For me though, that extra complication of adding a flag property and a test for it and thinking about the implications of this code in the Constructor->Setter->Open sequence can all be sidestepped with a method pair. Plus, I like leaving open the option to override the ‘property’ instead of being blocked by shadowing. That’s my style, but if Computed Properties are working for you then they’re working for you :slight_smile:

[quote=304432:@Greg O’Lone]Just out of curiosity… if they didn’t fire before the open event, how would you use them for user exposed properties? It’s a double edged sword where we’ve erred on the side which allows you to correct for it.

FWIW, changing this behavior could break countless projects, including a large portion of the web framework, so I find it unlikely that it will.[/quote]
The problem is that it didn’t do this when I first coded it, it only did this after I had reloaded Xojo and the project. If it had happened from the very first moment I had created the computer property (which was a regular property, then converted to computed), I would have instantly caught on. But the fact that it didn’t, the problem only occurred after a Xojo restart (the property was added a day before I restarted Xojo), took me 7 hours to narrow it down.

The property in question was used for adjusting the interface, it was never used during the open event of the control, only when the user chooses to view a different set of controls.

Indeed they do and that’s the reason why I love and use them too, but I can’t face wasting another 7 hours because of a change in my applications behavior that simply occurred from reloading Xojo.

Right now, I feel I need rigidity, and therefore I’ll revert to using getter and setters.

I’d like it more convenient too, and like you I spent hours (or rather days) trying to figure out a way that works for me.

Sometimes it even involves editing the code project file by hand when some pesky hidden default inspector behavior setting causes strange things – like a control being hidden by default (and me having spent another few hours searching the bug that caused my control to disappear …).

Good thing is my controls work now in the correct hierarchy, with all inheritances that should be. But yes, it took a long time and maybe one day that will become easier. The engineers often surprised me during the last years.

Couldn’t an init event be a solution – one that fires immediately when the instance is created, and later in the open event you could still do the visual set-up? This way the setters would not hit Nil, and old code that does not use the init event does not need to be changed …

Hi Sam

I ran into this ‘feature’ of computed properties recently while working on a RB to Xojo migration and solved it the same way.

I came to the conclusion that the computed properties implementation has changed at some point or the upgrade to Xojo fixed something that wasn’t working correctly in RB.

https://forum.xojo.com/37008-computed-properties-rb-xojo-differences

It seems to me that there should be a standard documented built in way in the IDE to handle this rather than relying on us adding flags…

Maybe add an auto-initialize time popup (At Creation, Immediately Before Open, Never) accessible via the Navigator located

  1. preferably on the righthand pane when you select the computed property parent item entry in the Navigator, so it would be obvious and hard to miss. That pane is currently unused and it would be hard to miss it there.

  2. or on the advanced TAB of the inspector for the item (which would be unique to computed properties, which is a downside)

If the computed is made to be visible via the Inspector behavior dialog for an instance value, to be set in the IDE, it should only allow At Creation and Immediately Before Open

It could default to teh current behavior

IMO It would be best if subtleties like this, that can easy be tripped over, be made as obvious (and controllable) as possible.

  • Karen

@Karen Atkocius; I like your suggestion, have an option in the IDE to let us specify the behavior! Have you made a Feedback Request?

@Kevin Gale; sorry to hear that man. Like Will, Ulrich and I, this change has already broken many existing projects, cost us developers hours (days in Ulrich’s case) to figure it out.

Properties are ALWAYS initialized to some state - so there’s really no possibility to have “Never”
They are EXACTLY like you wrote in a method

    dim i as Integer

or whatever name & type you used
“Never” would be incorrect & misleading

At creation is basically the same

The change that has everyone in knots is that previously code USED to behave as if it was

           dim w as new Window()
           w.SetProperties 

And “setProperties” only set ones that you had made visible in the property inspector for user properties

The change is that it sets them ALL - computed or not - visible or not

What needs to change to rectify this is that it needs to set only USER added properties that are visible in the inspector
Then life will be back to what it was before

And, as I wrote earlier in this thread, doing just that is not quite as simple as writing it in it this post

[quote=305006:@Sam Rowlands]@Karen Atkocius; I like your suggestion, have an option in the IDE to let us specify the behavior! Have you made a Feedback Request?

[/quote]
I realized a checkbox is all that is needed. See:
<https://xojo.com/issue/46410>

Norm,

Obviously as user code execution is involved in accessing computed properties, they need to be a special case for properties, and they really already are.

Right now the initialization can be a booby trap… and anybody can be a booby!

As you have seen on the forum this has caused experienced users problems and significant amount of time (and yes I have run into into), so it obviously needs to be addressed IMO.

  • Karen

How I wish it were that simple
This affects more than computed properties - it affect ALL properties - computed or not

[quote=305015:@Norman Palardy]How I wish it were that simple
This affects more than computed properties - it affect ALL properties - computed or not[/quote]

Obviously it could be done in the framework… But I assume you are saying that to be able to treat computed properties as a special case for initialization would mean major changes under the hood because of the current design.

  • Karen

no it cant …
we have no magic way to do this in the framework
we’d have about the same choices you do
a flag and some code to set the default
and if its a read only computed then there are other issues

the overriding issue that has caused all this is the change from NOT setting user properties if they were not visible in the inspector behavior to doing so
Fixing that should / would alleviate all this angst - I just havent got a decent and fast way to know if property X is or is not a user added one

Just to reinforce what Norm has said - not that he needs it - your Window initializers are all Xojo code. There’s no magic. It’s basically

Super.Constructor
// Set properties according to inspector
TextField1.Text = “Hello World”
RaiseEvent Open

Plus other stuff, but that’s about it. So the computed properties fire exactly like they would any other time.