Typical uses of blocking-wait are things like:
Code: Select all
on mouseDown
wait until the mouse is up
... do stuff ...
end mouseDown
on myAnimation
... run first part of animation ...
... play sound ...
wait until the sound is done
... further animations and sound playing ...
end myAnimation
Code: Select all
on executeShellFunction
get shell("... execute process that takes quite a while to finish ...")
end executeShellFunction
Code: Select all
on myAnimation
... run first part ...
... play sound ...
send "myAnimation2" to me in ... sound length seconds ...
end myAnimation
on myAnimation2
... run second part ...
... etc. ...
end myAnimation2
In other environments, you don't have a nice simple 'wait' primitive like this - you have to ensure when you are doing something like 'myAnimation' above or calling a shell command (which would most likely be done as a polling mechanism - like using open process instead of shell), that your app is in a state in which the user can't do things that might cause problems (like turning off interaction events and such), and your code has to be designed to prevent re-entrancy into what is going on (for example, if myAnimation is called as a result of a button click then in the 'threaded' variant you'd end up with two concurrent invocations of the animation which would likely cause a mess).
[ I should point out here that 'wait with messages' does not cause a problem - you have to script around getting messages you can't handle at the time of the 'wait with messages' so you are in the same boat as other environments, except that you don't have to thread your handlers which makes them easier to write and maintain ].
However, the problem is that the world has not evolved to really work in a 'blocking-wait' kind of way - having to support wait-without-messages (at least in the full generality it currently works in) means that some things cannot be implemented or leveraged in LiveCode because they do not work in a way which can be deferred in the way that is needed. (By deferred here I mean that many things want a response right now - they don't go "I need this information, please reply to me when you're ready and I'll wait for you" which is what the engine needs for blocking-wait).
There's one very good example of a feature which cannot be currently utilized in the iOS engine - filtering loads into the WebView control. When a web page is about to be loaded into a UIWebView, the webView:shouldStartLoadWithRequest: delegate method is invoked. This method requires there and then a YES or NO answer as to whether to proceed. Unfortunately, though, the LiveCode UIWebView control delegate cannot give the answer at that time because the method might have been invoked whilst a blocking-wait is in effect - instead it attempts to defer the choice, which ends up meaning things don't work right in some cases (particularly if frames are involved). The reason this can happen is that the iOS engine can only defer interaction events for the views it owns - there is not enough control (at the API level) of the eventqueue to only process certain events *and* iOS does not like you trying to work around this, it wants to be the sole manager of the eventqueue (if you try and do it yourself in a modal loop, many things stop working - this is why iOS is twin-thread, so things can always fallback to the root event loop).
(Another even better example is the hoops the engine goes through on iOS and Android with orientation changes...)
Now, given that you'd think most actions that cause such delegate methods to be fired are tied to user-interaction, you might think that if you can control the eventqueue (which you can seem to be able to do to a better degree in Cocoa than iOS) then things would be fine... However, my recent pokings around Cocoa caused me to develop a simple (WebView-based) sample where things are still not fine. On the Mac Desktop, there is a similar thing to UIWebView - WebView - which is a great deal richer in functionality. For example, you can attach a UI delegate that allows the host to manage JavaScript popup windows. However, this is again an example where 'blocking-wait' kills off being able to leverage this facility in the general way you might like. The WebUIDelegate has a method which will be called whenever the 'confirm()' JavaScript command is invoked. This method expects the implementor to return there and then whether the user clicked 'Yes' or 'No'. However, if when invoked a 'blocking-wait' is running the engine cannot send a message and so script cannot be run as a result. Given that JavaScript has timeouts which you can set, a web-page can quite happily ask for a 'confirm()' dialog at any point - unrelated to user input - and it easy to engineer a situation where such a request comes in during a blocking-wait (the example I engineered in the cocoa port I've been working on is this - HTML button with setTimeout of 3 seconds, invoking 'confirm()' when it fires; LiveCode button with 'wait for 5 seconds' - click HTML button then LiveCode button immediately afterwards, request for confirm dialog comes in during blocking wait).
So, in a nut-shell, in the modern world we have the problem that things can happen during a lifetime of an application which need an immediate response, but due to having to support 'blocking-wait' in the way we do, we cannot execute script to get that response. This in turn means many useful features we could leverage are out of reach unless we do something about the semantics of all blocking-wait operations.
I think the problem we face is this - at the moment blocking-wait actions currently give you a very firm guarantee: whilst the blocking-wait is in effect no script will run at all - i.e. you can be absolutely sure that your script state is the same before the wait as it is afterwards and that no part of your app will have run in the interim period. (To my mind this is a pretty hefty guarantee and I'm sure we've all written scripts that rely on it even without realizing.) Of course, it would be nice if we could just declare 'wait never blocks messages any more', however the chaos and breakage of code that would ensure I think would be significant...
At the moment I'm not entirely sure what the best solution is - as far as I can see, we certainly need to ease the semantics of blocking-wait, or restrict its domain of blocking-ness, or *insert some other suggestion to do with it* if we want LiveCode to be as well integrated with other components and libraries (such as native OS controls) as other environments allow. Indeed, it is even a bar to porting LiveCode to platforms - thus far I've managed to figure out how to make the engine work with the platforms we currently support, but both iOS and Android have significant wrinkles as a result and Cocoa is certainly seems to be skirting close to the same situation as those.
Therefore, with this post I hope to open up a discussion about it - please do ask questions and suggest things, I'm hoping that in answering and analysing we'll gain greater understanding of how to move from a world with blocking-wait to world where we have something like blocking-wait which doesn't actually block (well, not entirely at least) - blocking-wait-lite if you will .