Announcement

Collapse
No announcement yet.

GLOBAL -- Advice on best way...

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • GLOBAL -- Advice on best way...

    For the longest time I have been keeping all my GLOBAL variable declarations in an include file, same with equates.

    So my programs start with some includes like:

    Code:
    #INCLUDE "ALL_GLOBAL_VARIABLES.INC"
    #INCLUDE "ALL_GLOBAL_ARRAYS.INC"
    #INCLUDE "EQUATES.INC"
    Those files are now big and bloated and could use a good cleanup.

    I have started declaring globals and equates inside the primary function that uses them. Feels more modular and compartmentalized.

    From PB_CGI include:

    Code:
    FUNCTION LOAD_GCI_PARAMS_ARRAY() AS LONG
    
    DIM GLOBAL_GET_POST_STRING AS GLOBAL STRING
    
    LOCAL Post_Temp AS STRING
    LOCAL Post_Buffer AS STRING
    LOCAL ParamsString AS STRING
    GLOBAL ParamsCount AS LONG
    LOCAL ParamsCounter AS LONG
    LOCAL ParamsTemp AS STRING
    I assume there is no subtle difference between:

    DIM GLOBAL_GET_POST_STRING AS GLOBAL STRING
    vs
    GLOBAL GLOBAL_GET_POST_STRING AS STRING

    Any thoughts....

  • #2
    If and when I use a GLOBAL variable, the scope statement is placed OUTSIDE and PRECEDING any procedural code in the module.

    Code:
    .....
      GLOBAL  Z() AS LONG
    ...
    
    FUNCTION PhysicallyFirstFunctionInModule (....
    ...
    Just as a matter of style, I'd never define a GLOBAL variable within a SUB/FUNCTION .. END SUB/FUNCTION block. IMO too easy to lose.

    I "might" add a comment about GLOBALs used in a procedure...

    Code:
    FUNCTION Foo  (X AS LONG, Y AS LONG) AS LONG
    ' uses GLOBALS  A, B, C       '<<<< SO I know where it's getting these variables when  used
    LOCAL bar as long, baz as SINGLE
    ...
    Then again, there is that new compile time directive #UNIQUE which may address my concerns but I'm kind of a set in my ways.

    Note also: If using "older" posted code from here, be aware the way duplicate variable names (a global and a local ) has changed subtly across versions, although I don't think this has actually occurred in a while

    MCM
    Michael Mattias
    Tal Systems Inc.
    Racine WI USA
    mmattias@talsystems.com
    http://www.talsystems.com

    Comment


    • #3
      I do my GLOBALs in a #INCLUDE file for big programs or program suites (include in more than one program)

      It keeps the main program listing smaller for ease of editing - and you can flick between source files to look up stuff

      I make sure my GLOBALs are all listed together per use type - and all commented

      I make sure that the "AS" statements are all lined up - helps you eyeball things and see patterns

      I put a lot of thought into naming my GLOBALs using "_" etc. My GLOBAL names are very long. (Very occasionally I will shorten them because they are on one line of code but usually I just split the lines up)

      I usually put my Macros and Functions in another #INCLUDE file for similar reasons

      In fact my Macro #INCLUDES have my error processing and screen handling functions in too. And my copyright notices etc etc

      I have standard macro files, but I copy them into any new program suite and then I can feel free to change my 'standard' ones for that suite.

      I know of no difference between GLOBAL and DIM - except that DIM is local and GLOBAL is, well, global. I tend to only use GLOBAL even when it could be a DIM

      I would love to have a compile option which indicates when I have a GLOBAL that I do not use - helps debugging and makes for tidier code. Now I go through and comment out the suspected not uses and compile - see if I get an error.

      That is me on GLOBALS and #INCLUDES

      Kerry

      PS I just saw Michael's post. Yes all GLOBALS are in the program before PBMAIN - no exceptions
      Last edited by Kerry Farmer; 6 Dec 2017, 07:09 PM. Reason: Agreeing with MCM
      [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
      Kerry Farmer

      Comment


      • #4
        Putting GLOBAL variables in an INCLUDE file does not make a lot of sense to me. You can't share variables by name across modules anyway.

        Equates, declares, types/unions, sure... but not variables.

        MCM
        Michael Mattias
        Tal Systems Inc.
        Racine WI USA
        mmattias@talsystems.com
        http://www.talsystems.com

        Comment


        • #5
          Unless a variable needs to be shared between functions/subs, I find the use of STATIC variables solves many needs when data needs to be static, rather than dynamic, and it decreases the need for Global variables. Also the use of Global variables which are structures (TYPE) may help clean up code a bit and keep things a bit more organized rather than lots of individual Global variables.

          I also find that the use of Globals is important, there is a danger when one does not use a good naming convention to differentiate between local and global variables. Myself, I like to use a consistant prefix for all Global variables like this:

          Instead of:

          GLOBAL MyVar1&
          GLOBAL MyVar2&

          I use something like:

          GLOBAL App_MyVar1&
          GLOBAL App_MyVar2&

          The App_ prefix tells me immediately I am working with a Global variable, so they stand out in ones code in subroutines.

          While I think Globals are vital, I do think it is best to avoid using them too much. In my case for example with EZGUI 5.0 the main DLL with over 40,000 lines of code I define a good 400 to 500 Global variables. Most are defined at the beginning, but a good percentage are defined in different parts of the code just before routines which use them.

          If just a couple routines use certain Global variables, then defining them just before those routines makes a lot of sense and it makes tracking them easier. If a lot of routines throughout your code use certain globals, then defining them at the beginning makes more sense there.

          The same goes for constants. If used in only a few routines, then defining them just before those routines makes sense. If they are used throughout your code in a variety of routines, then defining them at the beginning of your code or in a separate include file makes sense there.
          Chris Boss
          Computer Workshop
          Developer of "EZGUI"
          http://cwsof.com
          http://twitter.com/EZGUIProGuy

          Comment


          • #6
            Like Michael, I declare all Globals and Equates at the start of a module. And I prefix Globals with "g_". (Obviously there is no need to prefix equates, they already require a specific initial character). Whether they are inline or in an include file is immaterial.

            --
            [URL="http://www.camcopng.com"]CAMCo - Applications Development & ICT Consultancy[/URL][URL="http://www.hostingpng.com"]
            PNG Domain Hosting[/URL]

            Comment


            • #7
              Thanks guys! Excellent food for thought - as always! You guys are the best!

              Comment


              • #8
                Yep, equates at top of module, right after metastatements. #INCLUDE "FRAMEWORK.EQU" followed by module-specific equates.

                > DIM GLOBAL_GET_POST_STRING AS GLOBAL STRING

                My version would be...

                DIM gsGetPost AS GLOBAL STRING

                gs= global string, gl=global long, etc.
                ss= static string, etc.
                s = local string
                l = local long

                I always DIM every variable and array inside every procedure, including globals. Old habit. I even use...

                DIM sArray() AS LOCAL STRING ARRAY

                ...which the compiler conveniently ignores (thanks BZ) and then I explicitly REDIM it with the actual dimensions.
                "Not my circus, not my monkeys."

                Comment


                • #9
                  Using objects is a good natural therapy for globalisation.

                  Comment


                  • #10
                    If GLOBAL scope is only needed in a few places, I like to use STATIC variables inside a subroutine and then add an argument for their value to Function/Sub calls if it's needed elsewhere. A ByRef argument can return a changed value if needed, else ByVal.

                    It can also help using user define Types, where all members becomes global via just one global variable. Like, GLOBAL g_MyType AS MyType so g_MyType.this and g_MyType.that gets global scope. I usually use this for custom controls, but also in other code.

                    I also try to separate code into include files as much as possible, because very large code files can be a nightmare when the bugs arrive. Not if, when. One include file per dialog keeps the doctor away..

                    Comment


                    • #11
                      Originally posted by Borje Hagsten View Post
                      If GLOBAL scope is only needed in a few places, I like to use STATIC variables inside a subroutine and then add an argument for their value to Function/Sub calls if it's needed elsewhere. A ByRef argument can return a changed value if needed, else ByVal.

                      It can also help using user define Types, where all members becomes global via just one global variable. Like, GLOBAL g_MyType AS MyType so g_MyType.this and g_MyType.that gets global scope. I usually use this for custom controls, but also in other code.
                      That's very like using INSTANCE variables in a CLASS.

                      Comment


                      • #12
                        If I have a global (usually an array) that only a small group of procedures needs to access, I'll create an SLL with just those procedures. That "encapulates" the global and makes it impossible to accidentally access it elsewhere, kind of like a "regional" variable declaration.
                        "Not my circus, not my monkeys."

                        Comment


                        • #13
                          From Kerry´s post above


                          I would love to have a compile option which indicates when I have a GLOBAL that I do not use - helps debugging and makes for tidier code

                          I absolultely agree! Obviously i cannot offer a compiler option, but my IDE has a feature listing local and global variables and indicating unused or a global/local mix, which can be a very diffcult to find error unless you made use of the 'UNIQUE" metastatement.


                          JK

                          Comment


                          • #14
                            Juergen, I suggested that in virtually every beta cycle. Bob's answer was "the compiler doesn't need to do things like that, because an external program can do them." Lean and mean. So back in the DOS days I wrote a "lint" program for my own PB coding style, to pick up things that the compiler didn't report. DIMmed but unused, declared more than once, missing close-quote at end of line (still an issue IMO), lots of stuff. I tried to make it more generic, to create a third-party product, but the variety of syntax that PB supports (like DIM vs. GLOBAL) is really wild. Kudos to you if you managed to handle everything that PB's parser can understand.
                            "Not my circus, not my monkeys."

                            Comment


                            • #15
                              "Kudos to you if you managed to handle everything that PB's parser can understand"
                              Think my PBCodec utility did a pretty good job, looking for the words LOCAL, GLOBAL or STATIC, etc in all DIM statements and same words alone, in such cases. Bob sure spoiled us with almost unlimited ways to write code, so worst part of creating a code parser for PB code is to cover them all.

                              Comment


                              • #16
                                Think my PBCodec utility did a pretty good job [of identifying unused GLOBAL variables]
                                Yes it did and in some cases (eg moi) still does!

                                MCM
                                Michael Mattias
                                Tal Systems Inc.
                                Racine WI USA
                                mmattias@talsystems.com
                                http://www.talsystems.com

                                Comment


                                • #17
                                  I find some humour in the political correctness of some methods of writing software. The oft maligned GOTO was regularly targeted by folks who were not even born when spaghetti code was the only way to write code. The solution is to use either an absolute "jmp" or a conditional "je, ja, jnz etc ...". You can also use a macro or similar "branch" to address the nonsense. Much the same comment on the vilification of GLOBAL variables, having seen some of the most rediculous archipeligos of call dependencies, it just takes a grasp of what SCOPE is about. There are some places where you DON'T want global variables, a re-entrant procedure for a thread, something common in internet based code but there are many places where this can be a pest.

                                  Instance handles are singular unique values in any process, usually an app has a main window that is unique to the app so in both instances a GLOBAL is by far the most convenient way to identify such handles. There is some code that is nearly impossible to write without them, subclass any control and the subclass return address which is defined well before the subclass can only be accessed by a GLOBAL.

                                  Rough rule is, if a variable is only ever used within a procedure (sub/function) always make it LOCAL and you don't run out of names. If a variable is needed across many procedures, make it a GLOBAL. The rest is hand holding and/or padding.

                                  Now with a re-entrant procedure, if you need something like a GLOBAL that can be accessed from any other procedure that branches off the start procedure, allocate a structure (udt) which you pass as an argument to any procedure called from it and the values in the structure remain available to everything from the bottom procedure up but without interfering with any other thread/process that re-enters the procedure. This way you can have multiple connections in internet style code where each started thread contains its own data independently from any other.
                                  hutch at movsd dot com
                                  The MASM Forum

                                  www.masm32.com

                                  Comment


                                  • #18
                                    > subclass any control and the subclass return address which is defined well before the subclass can only be accessed by a GLOBAL.

                                    Certainly not. There are other ways. For example, you can store the address as a property with SetProp and retrieve it in the subclassed procedure with GetProp, e.g.

                                    Code:
                                    ' ========================================================================================
                                    ' Processes messages for the subclassed Button window.
                                    ' ========================================================================================
                                    FUNCTION TextBtn_SubclassProc ( _
                                       BYVAL hwnd   AS DWORD, _                 ' // Control window handle
                                       BYVAL uMsg   AS DWORD, _                 ' // Type of message
                                       BYVAL wParam AS DWORD, _                 ' // First message parameter
                                       BYVAL lParam AS LONG _                   ' // Second message parameter
                                       ) AS LONG
                                    
                                       SELECT CASE uMsg
                                          CASE %WM_DESTROY
                                             ' // REQUIRED: Remove control subclassing
                                             SetWindowLong hwnd, %GWL_WNDPROC, RemoveProp(hwnd, "OLDWNDPROC")
                                       END SELECT
                                    
                                       FUNCTION = CallWindowProc(GetProp(hwnd, "OLDWNDPROC"), hwnd, uMsg, wParam, lParam)
                                    
                                    END FUNCTION
                                    ' ========================================================================================
                                    It doesn't matter what you use in your own code, this is your business, but if you intend to write reusable code, then the use of globals should always be avoided.
                                    Last edited by José Roca; 8 Dec 2017, 05:18 AM. Reason: spelling correction
                                    Forum: http://www.jose.it-berater.org/smfforum/index.php

                                    Comment


                                    • #19
                                      Large global arrays -- often UDTs -- are at the center of most of my large programs. I even have UltraEdit set up to highlight local, static, and global variables in different colors. Then again I'm the lone coder.
                                      "Not my circus, not my monkeys."

                                      Comment


                                      • #20
                                        Originally posted by Eric Pearson View Post
                                        Then again I'm the lone coder.
                                        Sometimes I feel like that - but then again we do have our forum

                                        But you are right - when I am in the middle of a program and the program has developed a mind of its own and I cannot make it do what I want and I have to totally concentrate and 'be' that program THAT is when I am the lone programmer - and that is when I am alive. I AM A PROGRAMMER

                                        I checked on the Lone Ranger - one of his rules is 'He always used perfect grammar and precise speech devoid of slang and colloquialisms' and that is almost a rule for programming.



                                        [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
                                        Kerry Farmer

                                        Comment

                                        Working...
                                        X