No, this is way too complicated to add. It would be better to just back out the feature, which was only added under the assumption that there was no detectable effect in doing so. The guarded/nonguarded state clearly protects more than just the variable state of the object, it also synchronizes the order of invocations of any methods called from within the method.
Rick On Tue, Aug 10, 2021 at 11:30 AM Rony G. Flatscher <rony.flatsc...@wu.ac.at> wrote: > To keep the best of both worlds I propose to allow to activate this > particular feature (defaulting methods to unguarded if the first statement > neither starts with EXPOSE nor with USE LOCAL) with a new option > "unguarded" on the options directive, i.e.: > > ::options unguarded > > Enclosed please find the intended patch (tested) with request for comment. > > Will update the documentation (rexxref) and the method directive test unit > accordingly. > > ---rony > > P.S.: With the patch applied the following program: > > say 'OPTIONS UNGUARDED set ...' > > do i=1 to 5 > m=.Test1~method("M"i) > say "m"i"~isGuarded:" m~isGuarded > end > > ::options unguarded > > ::class Test1 > > ::method m1 > say 'm1' > > ::method m2 > expose a > > ::method m3 > use local > > ::method m4 guarded > > ::method m5 unguarded > > > will yield the following (expected) output: > > OPTIONS UNGUARDED set ... > m1~isGuarded: 0 > m2~isGuarded: 1 > m3~isGuarded: 1 > m4~isGuarded: 1 > m5~isGuarded: 0 > > Without the new "unguarded" subdirective of the options directive in > effect method m1 will be guarded by default (the original behavior). > > > On 07.08.2021 18:28, Rony G. Flatscher wrote: > > Sleeping and thinking more over it I would suggest to remove this feature > altogether! The major reasing being that the Rexx philosophy (and ooRexx by > extension) should make coding as easy as possible for programmers. > > The default for methods (and related) has always been "guarded" such that > one would not have to write "guarded" to the method directive. With that > default only in very rare cases (in multithreaded scenarios) would one have > to write "unguarded" to a method directive. And if doing so one must have > an understanding of multithreading and the ramifications if someone would > want a method to run unguarded. > > Compare this to the current situation with this new feature on: in order > to fix BSF.CLS all of a sudden I had to add the keyword "guarded" to every > method to gain the default behaviour for ooRexx < 5.0 and thereby > re-enabling correct execution of GUI nutshell examples. > > Ad feature: originally it was thought to be helpful to programmers by > saving the programmers to write "unguarded" to a method directive for a > method that is known to be safe in unguarded mode thinking that methods > that have no direct access to the attribute pool (i.e. the method routine > would not start with "expose" or "use local") qualify for unguarded > execution not thinking about scenarios where this is not enough. > > To make it easy for the programmer (i.e. not having to know additional, > sometimes quite subtle, concepts that play a role in this context) I would > be in a strong favor to leave the default "guarded" in place. Then either > remove this new feature altogether or make it an explicit option a > programmer has to state ("::OPTIONS" with a new pair "guarded|unguarded"). > > What opinions have others? Do you concur? > > ---rony > > > On 06.08.2021 15:09, Rony G. Flatscher wrote: > > Background: In order for ooRexx programmers getting acquainted with > BSF4ooRexx/Java quickly there are numerous nutshell examples in > "bsf4rexx/samples". Most of these nutshell examples stem from observations > of students over time who should get help by demonstrating them how to > achieve something of interest with these (mostly brief) nutshell examples. > > One interesting problem has been the interaction from ooRexx with GUI > objects which must be carried out on the GUI threads in Java (the "awt > thread" or the "JavaFX Application thread"). Although they got the > necessary information about the architecture and what to do in ordert to > become able to send messages on GUI threads, they kept running into > problems, losing a lot of time (even months because they could not get it > working in more complex programs). > > To make a long story short, I came up with a message based solution, that > was very easy to understand and to employ for them. None of the students > ran into the GUI thread problems since then. > > The solution is an ooRexx class for awt (the Java "abstract windows > toolkit") named .AwtGuiThread and for JavaFX (a powerful GUI system) > .FxGuiThread, both subclassing a common superclass .AbstractGuiThread. > These classes allow one to send the ooRexx message > runLater[Latest](GUIreceiver, messageName, arguments) which get queued and > dispatched on the GUI thread later. > > The nutshell examples > "bsf4rexx/samples/3-090_update_awtSwing_GUI-from-non-GUI-thread.rxj" and > "bsf4rexx/samples/JavaFX/javafx_update_GUI-from-non-GUI-thread.rxj" > demonstrate how to employ this infrastructure. They have been working for > years without a problem. > > While working on BSF4ooRexx I stumbled over an error (not having run those > two examples for quite some time) which seems to indicate that ooRexx now > creates an error when being used from different threads: > > F:\work\svn\bsf4oorexx\trunk\bsf4oorexx\samples>3-090_update_awtSwing_GUI-from-non-GUI-thread.rxj > screenSize: [java.awt.Dimension[width=1920,height=1080]] > winSize : [java.awt.Dimension[width=800,height=200]] > xPos=[560] yPos=[440] > a REXXEVENTHANDLER::actionPerformed - starting Rexx thread > The SOME_REXX_CLASS class::updateGuiFromRexxThread - just arrived, GUI > thread: 23808 > The SOME_REXX_CLASS class::updateGuiFromRexxThread - now running on thread: > 7428 > *-* Compiled method "DELETE" with scope "Queue". > 5727 *-* msgQueue~delete(idx) -- delete the guiMsg object > 5637 *-* forward message "REMOVEMESSAGE" continue -- remove all GUI > messages of the same name targeted to the same object > 207 *-* .AwtGuiThread~runLaterLatest(label, "setText", "i", str) > Error 93 running > F:\work\svn\bsf4oorexx\trunk\bsf4oorexx\samples\3-090_update_awtSwing_GUI-from-non-GUI-thread.rxj > line 207: Incorrect > call to method. > Error 93.966: Incorrect queue index "1". > a REXXEVENTHANDLER::windowClosing - release lock ('closeApp=.true') which > will allow a blocked 'waitForExit' method to resume and return > > F:\work\svn\bsf4oorexx\trunk\bsf4oorexx\samples> > > and > > F:\work\svn\bsf4oorexx\trunk\bsf4oorexx\samples\JavaFX>javafx_update_GUI-from-non-GUI-thread.rxj > a REXXBUTTONHANDLER::handle - starting Rexx thread > The SOME_REXX_CLASS class::updateGuiFromRexxThread - just arrived, GUI > thread: 24244 > The SOME_REXX_CLASS class::updateGuiFromRexxThread - now running on thread: > 14124 > *-* Compiled method "DELETE" with scope "Queue". > 5727 *-* msgQueue~delete(idx) -- delete the guiMsg object > 5637 *-* forward message "REMOVEMESSAGE" continue -- remove all GUI > messages of the same name targeted to the same object > 194 *-* .FxGuiThread~runLaterLatest(label, "setText", "i", str) > Error 93 running > F:\work\svn\bsf4oorexx\trunk\bsf4oorexx\samples\JavaFX\javafx_update_GUI-from-non-GUI-thread.rxj > line 194: Incorrect call to method. > Error 93.966: Incorrect queue index "1". > > The ooRexx code where the error occurs looks like, lines # 5637 and # 5727 > are highlighted in green and bold: > > /* > ------------------------------------------------------------------------------------------------- > */ > -- method replaces existing target: this way only the latest sent message > will get executed! > /** This class method allows to define a Rexx message with its arguments that > should > * be processed on the GUI thread. Each invocation will create a new > <code>GUIMessage</code> > * from the supplied arguments and returns it for further inspection in > addition to queueing > * it for later execution on the GUI thread. Unlike <code>runLater</code> > this method will > * first remove any queued messages with the same target and the same > message name, before > * queueing this message. > * > * @param target the target object to receive a message on the GUI thread > * @param messageName the message name to send to the target on the GUI > thread > * @param indicator optional; indicates with "I" (Indivdual) that > the arguments > * are listed individually, "A" (Array) > indicates that the fourth > * argument is an array containing the arguments to supply > with the > * message on the GUI thread > * > * @return GUIMessage a GUI message object (modelled after ooRexx' > <code>Message</code> class > * that allows one to inspect the state of the message > (process completed, > * fetching a possible result, determining whether an > error occurred and > * inspecting it) > */ > ::method runLaterLatest class > use strict arg target, messageName, ... > > signal on syntax > if self~JavaGuiUtilityClz=.nil then self~setup -- make sure attributes are > initialized > > *forward message "REMOVEMESSAGE" continue -- remove all GUI messages of > the same name targeted to the same object* > guiMsg=result -- fetch returned GUIMessage object > msgQueue=self~msgQueue -- get message queue > msgQueue~queue(guiMsg) -- now enqueue current (latest) guiMsg > > if self~waitingToRun=.false then -- "runLater" not invoked yet? > do > self~waitingToRun=.true > self~invokeOnGuiThread -- make sure Java will dispatch Rexx message on > GUI thread > end > return guiMsg -- allows caller to get a hold of a possible > return value > > syntax: > raise propagate > > ... cut ... > > /* > ------------------------------------------------------------------------------------------------- > */ > -- method removes all GUI message objects > /** This private class method removes all GUIMessage objects from the message > queue that will be processed > * later when Java call backs on the GUI thread, that have the supplied > target and the supplied > * message name. > * > * @param target the target object to receive a message on the GUI thread > * @param messageName the message name to send to the target on the GUI > thread > * @param indicator optional; indicates with "I" (Indivdual) that > the arguments > * are listed individually, "A" (Array) > indicates that the fourth > * argument is an array containing the arguments to supply > with the > * message on the GUI thread > * > * @return GUIMessage a GUI message object (modelled after ooRexx' > <code>Message</code> class > * that allows one to inspect the state of the message > (process completed, > * fetching a possible result, determining whether an > error occurred and > * inspecting it) > */ > ::method removeMessage class private > use strict arg target, messageName, ... > > signal on syntax > if self~JavaGuiUtilityClz=.nil then self~setup -- make sure attributes are > initialized > > -- remove all occurrences of messages with the same messagename and the > same target > msgQueue=self~msgQueue -- get message queue > idx=msgQueue~first -- get index of the first item in the queue, if > any > do while idx<>.nil -- a valid index in hand ? > tmpItem=msgQueue~at(idx) -- fetch item, a GuiMessage > -- same target, same messagename? > if tmpItem~target=target, > tmpItem~messageName~caselessEquals(messagename) then > * msgQueue~delete(idx) -- delete the guiMsg object* > idx=msgQueue~next(idx) -- get index of next item in the queue > end > > guiMsg=self~createGuiMessage(arg(1,"array")) -- create and return GUI > message object > return guiMsg -- allows caller to get a hold of a possible > return value > > syntax: > raise propagate > > None of the methods of these three classes are marked as unguarded such > that in the past if one method executes no other can do so in parallel, > inhibiting concurrent access of the queue. > > However, I recall that there was a change in ooRexx 5.0 that if methods do > not have an expose keyword statement than unlike earlier versions of ooRexx > such expose-less methods will be made unguarded. > > Yet, as in this real use case this change may bring incompatibilities for > existing programs (BSF4ooRexx has been around for more than 10 years). The > problem lies in getting and using the queue in different threads because of > this (at the time of devising the solution unforeseen) as no default > blocking of methods takes place. > > To double-check I added manually "guarded" to all methods of the classes > that play together here and doing so, made the nutshell programs work again. > > --- > > The reason I bring this forward is twofold: > > - the change may break existing programs and programmers may be > clueless as to why that happens and therefore not know how to solve it, > - it should be discussed whether keeping this change, but if so it > needs to be prominently communicated as the cause may be too subtle for > many, especially if using ooRexx code for which they do not have the > source: > - one solution may be to have a new OPTION unguared|guarded > determining how expose-less methods should be treated; this way this > default to unguarded behavior needs to be activated explicitly making > the > programmer aware of it, yet older programs still would function with the > default to guarded behavior that was in place in erarlier versions of > ooRexx, > - another solution would be to not only analyze whether the expose > statement exists, but in the case where it does not exist also analyze > whether messages to self occur and if so leave the method guarded; > however > this bears the problem that one could use an object that refers to self > such that the problem might surface nevertheless. > > Any thoughts, ideas, suggestions, conclusions? > > ---rony > > > _______________________________________________ > Oorexx-devel mailing list > Oorexx-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/oorexx-devel >
_______________________________________________ Oorexx-devel mailing list Oorexx-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/oorexx-devel