Announcement

Collapse
No announcement yet.

Basic Programming Question

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

  • Michael Mattias
    replied
    The problem is though that if you are not careful with the naming convention used, you may confuse global and local variables and this would cause problems
    Well, "a" problem, perhaps, but hardly "the" problem.

    I'd consider 'data integrity' the principal problem, not only for the obvious result of incorrect output, but because these problems in any re-entrant circumstance are essentially impossible to re-create on demand, and don't occur each and every time the program runs... that is, they are virtually impossible to "find and fix."

    MCM
    (who actually does have problems remembering GLOBAL data names)

    Leave a comment:


  • Cliff Nichols
    replied
    Personally until my post back at #15 Yesterday, 09:56 AM
    which is because of my recent issue(s) involving GLOBALS, I used them exclusively for sharing info between subs and functions.

    Eventually over years of use, Re-USE, and projects getting larger, I fell into the debate myself of GLOBAL vs LOCAL because of THREADS.

    So far, it is true because depending on timing and other factors, I have come to realize that if the variable is in the midst of being set, and another thread gets its "Time-Slice" and is also setting the same variable, then the result would be "Inconclusive"

    My advice, is use what works best for you, but when things go awry, then keep it in the back of your mind "What if its my variable?" when you can not figure out when your code "Does NOT work as advertised"

    And YES I am still "Guilty as Charged" when it comes to GLOBALS on all my projects just to meet timelines (or to suit the purpose of the moment), while I "Secretely" work on correcting that idea on a future version that will be released when its ready and as stable as "What CURRENTLY is known to be stable in the current release"

    Leave a comment:


  • Chris Boss
    replied
    Paul answered your question best.

    Global variables are there for a reason.

    They are very useful for sharing data among subroutines/functions.

    The problem is though that if you are not careful with the naming convention used, you may confuse global and local variables and this would cause problems.

    The solution ?

    Use a unique prefix for all global variables and you not have any problems.
    (I like th use the App_ prefix)

    ie.

    GLOBAL App_MyGlobal1&
    GLOBAL App_MyGlobal2&

    Some like to use the prefix g:

    ie.

    GLOBAL gMyGlobal1&
    GLOBAL gMyGlobal2&

    Personally, I strongly prefer the use of a prefix with an underscore (_) character after it. If you like the g prefix, use:

    ie.

    GLOBAL g_MyGlobal1&
    GLOBAL g_MyGlobal2&

    A prefix with an underscore is more readable (noticable) at a glance and you are less likely to confuse it with any local variables.

    Leave a comment:


  • Michael Mattias
    replied
    It took me a while to "get the feel" for "here's an event, coming at you, Deal With It!"

    That's in spite of the fact I had previous experience with the model from working on minicomputers (younger members: these don't exist anymore) and mainframes running "message-based systems" (eg IBM CICS, Burroughs GEMCOS or COMS).

    The good news is, you will probably have that same "Eureka!" moment I had when it just magically all came into focus and made perfect sense from that day forward.

    MCM

    Leave a comment:


  • Lee Bergeron
    replied
    Thanx to all who replied - This has really opened my eyes to Event Driven programming. My programs are usually relatively small (utility based) and my techniques are not very high level. I still do most of my programming in "DOS Type" languages so the concepts of event driven programming all need to be learned. With every new Windows Program I try to learn more but this can be very daunting. Is there any instructional books out there explaining event driven programming techniques without being language specific? Otherwise I keep learning bit by bit through these Forums.

    Leave a comment:


  • Michael Mattias
    replied
    try to write mostly self contained functions. Not only are these more portable, but I find I can optimize and modify them without causing problems elsewhere in the code.
    Frustrating, isn't it? "Gee, I already wrote, tested and debugged code to do [almost] exactly what I want to do again, but I can't re-use my work."


    I still find it easier to use globals for some thing
    The Truth: I use one GLOBAL variable and even more than one STATIC in one of my major commercial applications (the EDI Pal(tm) ANSI ASC X12 Viewer-Editor-Printer).

    However, I always start developing any procedure on the assumption I will want to re-use it in some way, and ask myself how I can create that procedure using only stack-based (LOCAL or passed parameter) variables.

    Leave a comment:


  • Cliff Nichols
    replied
    Just for grins, this is the way I do it.
    Code:
    #COMPILE EXE
    #DIM ALL
    #IF NOT %DEF(%WINAPI)
        #INCLUDE "WIN32API.INC"
    #ENDIF
    %IDD_DIALOG1 =  101
    %IDC_BUTTON1 = 1001
    %UNKNOWN_VALUE = -1
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    DECLARE FUNCTION SetGetValue(ValueToSet AS LONG, ReturnValue AS LONG, ResetValue AS LONG) AS LONG
    
    CALLBACK FUNCTION ShowDIALOG1Proc()
        LOCAL LocalReturnValue AS LONG
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                ' Initialization handler
    
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
            CASE %WM_COMMAND
                ' Process control notifications
                SELECT CASE AS LONG CBCTL
                    CASE %IDC_BUTTON1
                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
    '                        MSGBOX "%IDC_BUTTON1=" + FORMAT$(%IDC_BUTTON1), _
    '                            %MB_TASKMODAL
        SetGetValue %UNKNOWN_VALUE, LocalReturnValue, %UNKNOWN_VALUE
        MSGBOX STR$(LocalReturnValue)
                        END IF
    
                END SELECT
        END SELECT
    END FUNCTION
    
    FUNCTION PBMAIN()
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
        LOCAL LocalReturnValue AS LONG
        DIALOG NEW hParent, "Dialog1", 70, 70, 96, 23, %WS_POPUP OR %WS_BORDER OR _
            %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_SYSMENU OR %WS_MINIMIZEBOX OR _
            %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME _
            OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
            %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
            %WS_EX_RIGHTSCROLLBAR, TO hDlg
        CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Button1", 10, 5, 75, 15
    
        SetGetValue 100, LocalReturnValue, %TRUE
        SetGetValue %UNKNOWN_VALUE, LocalReturnValue, %UNKNOWN_VALUE
        MSGBOX STR$(LocalReturnValue)
        
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------
    
    FUNCTION SetGetValue(ValueToSet AS LONG, ReturnValue AS LONG, ResetValue AS LONG) AS LONG
         ON ERROR GOTO ErrHandler
         STATIC CurrentValue AS LONG
         SELECT CASE ResetValue
              CASE %False, %UNKNOWN_VALUE
                   ReturnValue = CurrentValue
              CASE = %TRUE
                   CurrentValue = ValueToSet
                   ReturnValue = CurrentValue
         END SELECT
         FUNCTION = %False        'Pass False if no error in function or True if error in function
         EXIT FUNCTION       'Escape function so not to trigger error log
    ErrHandler:
         MSGBOX "An Error Occurred"
    END FUNCTION

    Leave a comment:


  • Gösta H. Lovgren-2
    replied
    Originally posted by Lee Bergeron View Post
    Thank for all the replies - but noone answered the initial question. I wasn't trying to start another debate over Global vs Local variables. My question is very simple - how does one do anything in a CALLBACK without having Global variables. With regular FUNCTIONS I can pass the Local Variables to them and return them back changed, not so with CALLBACK Functions (I assume).
    When Globals are mentioned in almost any discussion here, Lee, it soon descends into Global vs Local wrestling match.

    To answer the question "how does one do anything in a CALLBACK without having Global variables.", one has to pass the variables. As has been suggested, a Type containing all the Globals is (most?) convenient.

    Here's a clumsy example where the Global_Variables Type is Local in the Callback then passed in Calls to Function or Subs. So any Sub/Function called has, in effect, Global variables.

    '
    Code:
    'PBWIN 9.00 - WinApi 05/2008 - XP Pro SP3
    #Dim All 
    #Compile Exe  
    #Include "WIN32API.INC"
    '
    Type Global_Variables
       Variable1  As Long
       Variable2  As String * 1000
    End Type         
     
     
    %Id_Exit_Btn = 1000
    %Id_Sample_Textbox = 1001
    %Id_Show_Result_Btn = 1002
    ' 
    Macro Common_Locals 'Macro easier than retyping and maintains coding consistency
      Global Dlg_hght, Dlg_Wd As Long 'Global in case want to use in Controls
      Local hDlg As Dword
      Local Row, col, hght, wd, Longest,ctr, ln, ln1, i As Long
      Local  l, s As String
    End Macro  
    '
    CallBack Function Dialog_Processor () As Long             
      Common_Locals                     
      Local G As Global_Variables
       'test of passing
       g.Variable1  = 10  '<< Set "Global" for testing      
     
      Select Case CbMsg     'This is TO determine the message TYPE 
         Case %WM_COMMAND  'This processes command messages
           Select Case CbCtl
             Case %Id_Show_Result_Btn 
                Call Testing_Global_Concept1(CbHndl, G) '<< Pass the Callback Handle & the "Globals" to the function
                  ? g.Variable2 , , Str$(g.Variable1) & " in " & FuncName$  '<< see "Globals" returned
             Case %Id_Exit_Btn
               Select Case CbCtlMsg        
                  Case 0
                    Dialog End CbHndl
               End Select
           End Select
      End Select
    End Function               
    '
    Function Testing_Global_Concept1 (Hdl As Dword, G As Global_Variables) As Long
       Common_Locals    
        Control Get Text Hdl, %Id_Sample_Textbox To l$
         ? l$, , Str$(g.Variable1) & " in " & FuncName$
         g.Variable1 = 100 '<< Reset "Global"
         g.Variable2  = Str$(g.Variable1 ) & " Returned"  & $CrLf  & l$ '<< set another "Global"
     
     
    End Function
    '
    Function PBMain
      Common_Locals
      Dlg_hght = 400
      Dlg_Wd = 400
      Dialog New Pixels, hdlg, "Demo", , , Dlg_Wd, Dlg_Hght, %WS_SYSMENU To hdlg 'centered
     
      Row = 10
      col = 10
      Wd = 40
      Hght = 12
      Control Add Label, hdlg, -1, " Name & Address ", Col, Row, Wd, Hght
     
      s$ = "Brown, Kevin" & $CrLf & _
           "123 PBWin Avenue" & $CrLf & _
           "PowerBasic, FL 12345"
     
      Col = Col + Wd + 10 'just past label 
      Hght = 15 * 10 'Plenty room for 10 lines of text
      Wd = Dlg_Wd - 40 - 30 'minus the label and leave a little
      Control Add TextBox, hdlg, %Id_Sample_Textbox, s$, Col, Row, Wd, Hght, %ES_WantReturn Or %ES_MultiLine
     
       hght = 25   
       Wd = Dlg_Wd - 20
       Col = 10 'center
     
       Row = Dlg_hght - (Hght * 2) - 4 'Just off bottom
         Control Add Button, hdlg, %Id_Show_Result_Btn, "Show Textbox Results", col, row, Wd, Hght
     
       Row = Dlg_hght - Hght - 2 'Just off bottom
         Control Add Button, hdlg, %Id_Exit_Btn, "Abandon Ship", col, row, Wd, Hght
     
         Dialog Show Modal hDlg   Call Dialog_Processor
    End Function
    '
    =========================================
    An ambassador is an honest man
    sent to lie abroad for the commonwealth.
    Sir Henry Wotton
    =========================================
    Last edited by Gösta H. Lovgren-2; 6 Nov 2008, 09:49 AM.

    Leave a comment:


  • jcfuller
    replied
    One way to do it.
    James

    Code:
    '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
    'SED_PBWIN
    '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
    
    #COMPILE EXE
    
    %IDTEXT = 101
    FUNCTION PBMAIN() AS LONG
    	REDIM sNames(1 TO 10) AS STRING
        LOCAL hDlg   AS DWORD
        LOCAL Result AS LONG
    	
    	ARRAY ASSIGN sNames()="One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"
        '  Create a new dialog template
        DIALOG NEW 0, "Enter a Number Name",,, 160, 50  TO hDlg
        '----------------------------------------------------------------
        '  Add controls to it
        CONTROL ADD TEXTBOX, hDlg, %IDTEXT, "", 14,  12, 134, 12
        CONTROL ADD BUTTON, hDlg, %IDOK, "OK", 34, 32, 40, 14, _
            %BS_DEFAULT OR %WS_TABSTOP
        CONTROL ADD BUTTON, hDlg, %IDCANCEL, "Cancel", 84, 32, 40, 14 _
           
    	DIALOG SET USER hDlg,1,VARPTR(sNames(1))
    	DIALOG SET USER hDlg,2,UBOUND(sNames)
        '----------------------------------------------------------------
        '  Display the dialog
        DIALOG SHOW MODAL hDlg , CALL DlgProc TO Result
    
        '----------------------------------------------------------------
    
    END FUNCTION
    
    CALLBACK FUNCTION DlgProc() AS LONG
    	LOCAL idx, ub AS LONG
    	LOCAL sPtr AS STRING PTR
    	LOCAL sText AS STRING
    	SELECT CASE CB.MSG
    		CASE %WM_COMMAND
    			IF CB.CTL = %IDCANCEL THEN
    		        DIALOG END CB.HNDL, 0
    			ELSEIF	CB.CTL = %IDOK THEN
    				CONTROL GET TEXT CB.HNDL,%IDTEXT TO sText
    				DIALOG GET USER CB.HNDL,2 TO ub
    				DIALOG GET USER CB.HNDL,1 TO sPtr
    				FOR idx = 0 TO ub-1
    					IF @sPtr[idx] = sText THEN
    						? "We Have a Match at " + FORMAT$(idx+1)
    						EXIT FOR
    					END IF	
    				NEXT idx	
    			END IF
    	END SELECT		
    	
    
    END FUNCTION

    Leave a comment:


  • Michael Mattias
    replied
    >how does one do anything in a CALLBACK without having Global variables.

    By recognizing that given a window handle (eg CBHNDL) you can get any piece of information in any control.

    Eg do something based in the current selection in a listbox
    Code:
    CALLBACK FUNCTION DlgProc () 
    
            CASE somemessage 
                  CALL  update_Text (CBHNDL) 
    
             .....
    FUNCTION Update_text (BYVAL hWnd AS LONG) 
    
        LISTBOX GET SELECTION TEXT   hWnd, %ID_LISTBOX to s 
        CONTROL SET TEXT  hWnd, %ID_LABEL, S
    Or, by using the "DIALOG SET USER" values

    Code:
        DIALOG NEW  .... TO hDlg 
        DIALOG SET USER hDlg, 1, value 
        CONTROL ADD...
        DIALOG SHOW....
    
    CALLBACK FUNCTION DlgPRoc 
    
         CASE importantMessage 
              DIALOG GET USER CBHNDL, number TO value 
              value = newvalue 
              DIALOG SET USER CBHNDL, number, newvalue
    Go look thru some of my demos in source code forum. I do stuff like this all the time.

    MCM

    Leave a comment:


  • Lee Bergeron
    replied
    Thank for all the replies - but noone answered the initial question. I wasn't trying to start another debate over Global vs Local variables. My question is very simple - how does one do anything in a CALLBACK without having Global variables. With regular FUNCTIONS I can pass the Local Variables to them and return them back changed, not so with CALLBACK Functions (I assume).

    Leave a comment:


  • Michael Mattias
    replied
    > classic example of Threads and globals, which I am just now beginning to understand

    You were lucky, you were pretty much forced to create a compileable 'small' program to show the problem, and what you ended up with was a wonderful instructional piece, where you can see the problem basically on one screen.

    We've had other people run into the same problem... except in their cases, it was in a 20,000 line program which had been in production for two years and was now being 'enhanced' to use multiple threads of execution.

    Track down one of those and you'll see why I said you were lucky.

    Leave a comment:


  • Cliff Nichols
    replied
    I am sure that MCM and others will correct me on mistaken thoughts on this, but such is the debate of Global vs Local

    In the past I used GLOBALS to store a value to be accessed by multiple functions (and over the years similar programs and re-using code it can become hard to track down when a problem)

    I also started using "Headers" along with "Includes" to try and group common things together and not cause conflicts (but after time, one would depend on another, and if not in the right order, would not compile)

    Which is why I put all my declares in a "Header" and the functions in a "Include", and slowly moving back to "If not included, then define and include it"

    That is a lil above and beyond what your asking, but the basics of keeping local vs global is the variable can be corrupt (or in the midst of changing) depending on where it was accessed from.

    MCM pulls the classic example of Threads and globals, which I am just now beginning to understand, but if you think of it as 2 copies of the same program, but able to access one variable then if the timing is right, then program 1 could be in the midst of changing the variable, when the OS switches to program 2 and it reads, so it would be like

    Variable = "WHATSMYVALUE"
    Program1 = "WHATSMYVALUE" = 123...4
    Progam2 = "WHATSMYVALUE" = (interupt between 3 and 4) so the return I 123
    and before the time is up change to 1235
    now Program1 reply is 1235
    sort of thing

    How often does this happen? (not much...but when it does it will drive you NUTS trying to find a "Bug" when it is not a bug, but just the procedure of how things work

    Nowdays, I am working on thinking not only local variables (both for readability, but also for keeping the value correct depending on what accessed it) is the thread "Or copy of the program" keeps its own value and not a global (which could change)

    (last statement could be wrong, but best I can explain it with my knowledge)

    All in all if you can post a example of your particular question, I bet that one or more of us can show you "The many ways to skin the cat" to achieve it

    Leave a comment:


  • Barry Marks
    replied
    Something to consider in deciding whether to use globals and how much to use them is the size of your program. If, like me, you're only writing small, simple programs, it simply makes no difference whether you use globals or not as long as you're comfortable with what you're doing and understand the ins and outs of it.

    As programs become larger and more complex then the avoidance of global variables begins to make a lot more sense. But, except in special situations as mentioned in some earlier posts, sometimes they're still quite useful and can make for simpler programs.

    I think the important thing to remember is that there are no rules in programming unless you're being paid to do it by a company which imposes rules, which most do. Doing it for yourself there are no rules; there are only guidelines.

    Many of the guidelines were developed to solve problems and simplify programming and to help you avoid traps but they're always just guidelines.

    You decide, but decide after you know how to do it either way.

    Barry

    Leave a comment:


  • Conrad Hoffman
    replied
    I tend to use a lot of globals and haven't had any major problems, but I don't write that many programs. As I come up with more programs I'm starting to try and reuse code and that's where globals can be annoying. In my more recent stuff, I try to write mostly self contained functions. Not only are these more portable, but I find I can optimize and modify them without causing problems elsewhere in the code. I still find it easier to use globals for some things, and I don't agonize much when I use them, but I'm also learning to think about the future, not just what I'm doing at the moment.

    Leave a comment:


  • jcfuller
    replied
    This is one area where the new 9/5 compilers really shine.
    Create a class and use instance variables.
    You have Class access to all variables and portability at the same time.

    James

    Leave a comment:


  • Rodney Hicks
    replied
    Have you had problems because you have used globals? I mean problems that could only be rectified by not using globals.

    I myself do not hesitate to use globals when they are the best tool for the job, just as Paul states.

    Globals, though, can become a burden, and when that happens, check out other options.

    As Michael points out, there are times when globals are restrictive, and if you find yourself living during those times, use the most suitable tool. Most suitable to you, the program, your needs, comfort level, programming level, and program requirements.

    Like any of the tools in the Power Basic toolbox, you have to respect the conditions that you use them in.

    There is nothing wrong with wanting to program without globals, but to make your task harder to do so (other than the learning curve) than it has to be is maybe not a good programming practice either.

    Leave a comment:


  • Michael Mattias
    replied
    >There is nothing wrong with using global variables as long as you are careful with them

    AND

    You can live with your code not being re-entrant... which means if you ever want to support multiple simultaneous instances of a dialog, or change your application to be multi-threaded, you will have a lot more changes to make than simply an extra "DIALOG NEW" or "THREAD CREATE" statement.

    Also, when you use GLOBALs, the functions you write are more than likely not portable.. that is, you won't necessarily be able to use them in other applications or move them to a separate DLL within this application without making some other changes.

    See also: Lunch, Free; no such thing as


    MCM

    Leave a comment:


  • Chris Holbrook
    replied
    Lee, if you post compileable source code I'm sure that within a day or two you will discover at least two ways of do what you want! It does not have to be your whole application - just enough to illustrate the problem.

    Leave a comment:


  • Paul Squires
    replied
    There is nothing wrong with using global variables as long as you are careful with them. Try prefixing them with a "g" or something so that you can distinguish them from other variables and not to confuse them with local variables. I put all of my globals into a global TYPE structure and then I only need to deal with the one global TYPE (i.e. Global g As MyGlobalsTYPE)

    Anyone who insists on telling you that globals should never be used is not using the language to its fullest potential. Why hack in weird methods to a program just to avoid globals? Seems backwards to me. Use the language's abilities to get the job done - work with the language rather than against it.

    Leave a comment:

Working...
X