Global Variables. Regardless of the relative merits of Arrays vs Object. I would like to relay my dislike in general of Global variables. I have been working with 4D since before the concept existed-since 4D V2(Globals came in with V3). Yes i am one of the old boys.
Back then we did not have multiple processes and when V3 arrived we were all amazed and in awe of the ability to have multiple processes and I think we all went mad for interprocess(global) variables.(i think we all had singing dancing palettes on the screen doing fancy things to update themselves from other processes). Now if we were working in Javascript the concept of a global variable would very much be considered something to be avoided like the plague. Global variables are extremely useful but also extremely prone to problems, and over the past couple of years-any javascript tutorial tells you to try and avoid them, in 4D I have really cut down on my use of them. In my opinion a global variable should in general only be used for two things. 1) You want to set a value(or group of values) and through the life of the programme they do not change once set(so here you are using them like a constant) 2) You want to maintain an array that will be written to by multiple processes. With point 2 you must protect the arrays with semaphores so only one process alters the arrays at any one time-and often where these are used there might be other ways to do it. I have just this week been dealing with 2 different structures where the liberal use of interprocess arrays has lead to problems. Problems that do not show up in testing and probably show that that the way the routines has been used has changed over time. In both cases-different companies-different programmers-different stuff an error shows up just occasionally. In one of those systems discussion with the client shows that the usage of interprocess variables has caused ‘strange’ unexplained un-investigated things to happen where process A is changing the contents of <>Variable just at the point when process B is about to send the contents of <>Variable that process B had set to a document (‘sometimes we get a situation where the same order document is created twice’!!)..and they have just restarted the machine to get rid of the problem in the past(a practice that means you think the problem is 4D not the way the code is written). Simply protecting the handling so only one process at a time can modify the interprocess variables and arrays would have avoided all this. I suspect the original programmer never intended the functionality to be running in multiple processes at the same time and used interprocess arrays to (I think) make it easier to display the data on a form that is in a different process. Beyond the idea of a form in a different process i don’t see any purpose in the arrays in this case being interprocess-they are being constantly changed and as such should at best have been process arrays, In fact in a modern context(this was written way before that) where we have been able to pass pointers to local variables since 4D V11(??-maybe it was before that) I would generally argue that programming using locals is much better-and that could be local objects or local arrays. These really show that an interprocess array was used for convenience where it was not really needed and changes to code did not include a proper assessment of the impact-just because you can do something and it works once does not mean it is tested or fit for purpose. In most of my code over the past few years I have moved so far away from <> variables that if i have more than a few-maybe a variable holding the user name or something like that which does not change(and even there I use a function ..UTIL_GetUser(“Name”)..). I have even moved largely away from process variables and arguable could move further from them by not using variable names on screen objects. Convincing clients to let me change their code and actually changing it is not easy-in one case about the changes to the code are on a live system running uncompiled and this morning i am going to be attempting to apply a knife to this code. Most code i write now is ‘self contained’ -I attempt to set all values used in the method is passed in to the code -either as parameters or an object or a pointer to something so that i end up with something more like a javascript function. Myreturn:=MyMethod(something;something;something). Using this style of coding means i am far more likely to get an error if there is one EVERY TIME rather than a head scratching randomly appearing one and my code does not rely on the perceived value of a variable. Consider If(<>SOmething=1) //do something end if as soon as you have more than process where <>something is set you run the risk that at some point process A will set <>something to 1 and before it tests if <>something =1 process b changes <>something to 0 so you put a semaphore to stutter your code.. if you write if(something=1) //do something end if //now process B can do whatever it likes with something and process A will not be affected but you still run the risk that somewhere you call this function before you have C_Longint(something) and something is not initialised. Even if ‘something’ should be initialised to the value of '<>something' this should be done at the start of the process and never use '<>something’ in the code. When i find code that uses '<>something' or ‘something'i have to look to see where something is set what changes it and work out everything about it. if you write C_LONGINT($something) if(Count parameters>=1) $something:=$1 end if if($something=1) //do something end if You have code that is not dependent on the value of a variable it is only dependent on a value being passed in, and that might mean that the calling method also can use a local. This means i only need to see where my code is called and check that it is passing a relevent value to the code-much easier to track down a fault. This is a simple ‘one step’ example but I frequently see code chains like this. Methoda sets var-calls-method b-calls-method c-calls method d-and method d has if(var set in method a), and that is really where this chain of handling becomes a mess-we have method and the variable is set 3/4 levels up or worse set at startup in the code. If you pass an object the concept can become of course much more flexible, and slowly i am trying to adopt an object passing approach C_OBJECT($Something) If(Count parameters>=1) $Something:=$1 end if if($Something.setting=1) //do something end if Becomes much easier to read(no unpacking the object here). After all its used extensively in javascript where passing json normal and with V16 now using dotted notation for getting at object item is a big encourement to utilize this(yet to test that out myself). Are other people taking this approach to the use of variables. How easy are you finding it retro-fitting it to existing code? Nigel Greenleee > On 18 Jul 2017, at 16:29, Chip Scheide via 4D_Tech <[email protected]> > wrote: > > Long ago - and I am pretty sure the code has been lost to time - > in v2.2.3 (I think) I wrote code to do binary searching on a selection, > as at that time Search Selection (the old command name) was sequential, > but sorting the selection was indexed. > > Even with the overhead of managing the pointers, and stepping through > records to find all matching records in the selection, as memory > serves, it was faster (interpretedly) to use the binary search on a > selection size of beginning at 6-8 records. > > For those who care, an outline of a binary search (on records in > selection) > The following was written off the stop of my head, in the email editor, > BUT it gets to the basics of a binary search on a selection in 4D. > > - get size of selection ($Selection_Size). > - make sure it is sorted on the field you want to search on. > > repeat > $Current_record:= int($Selection_Size/2) > > repeat > goto selected record([table];$Current_record) > case of > :($Current_record>=$Selection_Size) or ($Current_record<=1) > $Not_Found:=true > :([table]field = Value) // found it create collection of > matching records > add to set([table];"Matching") > $previous:=$Current_record > $Next:=$Current_record > > repeat > $previous:= previous-1 > goto selected record([table];$previous) > > if ([table]field = Value) // found it create collection of > matching records > add to set([table];"Matching") > else > $previous:=0 > end if > until($previous=0) > > repeat > $$Next:= $Next+1 > goto selected record([table];$Next) > > if ([table]field = Value) // found it create collection of > matching records > add to set([table];"Matching") > else > $Next:=Selection_Size > end if > until($Next= Selection_Size) > $Mo_More_Matches = true > :([table]field > Value) // Not found current record value > > search value > $Current_record:=int((1+$Current_record)/2) > :([table]field < Value) // Not found current record value < > search value > $Current_record:=int((Selection_Size+1+$Current_record)/2) > end case > until ($Not_Found)) or ($No_More_Mathes) > > At this point the set "Matching" contains all records matching the > criteria, or nothing. > > On Tue, 18 Jul 2017 22:16:18 +1000, David Adams via 4D_Tech wrote: >> >> And, lest anyone forget, you can use binary search logic on sorted >> selections with GOTO SELECTED RECORD. Why not? > --------------- > Gas is for washing parts > Alcohol is for drinkin' > Nitromethane is for racing > ********************************************************************** > 4D Internet Users Group (4D iNUG) > FAQ: http://lists.4d.com/faqnug.html > Archive: http://lists.4d.com/archives.html > Options: http://lists.4d.com/mailman/options/4d_tech > Unsub: mailto:[email protected] > ********************************************************************** ********************************************************************** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:[email protected] **********************************************************************

