I have created several Powerbasic Windows Applications where I have used GLOBAL Variables exclusively. There has been much discussion that this is not a preferred method and LOCAL Variables should be used. How does one then get anything "done" in a CALLBACK Function without any access to Variables (Arrays, etc) defined as LOCAL to PBMAIN? EXAMPLE - User enters a Name in a Textbox Control. I want to check that name in the CALLBACK to see if it is in the Customer Name Array previously loaded (LOCAL ARRAY). Is there a way to do this without using a GLOBAL ARRAY?
Announcement
Collapse
No announcement yet.
Basic Programming Question
Collapse
X
-
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.Paul Squires
FireFly Visual Designer (for PowerBASIC Windows 10+)
Version 3 now available.
http://www.planetsquires.com
-
>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
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
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.Rod
In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.
Comment
-
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.
Comment
-
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
Comment
-
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 itEngineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Comment
-
> 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.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
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).
Comment
-
>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
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
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
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
Comment
-
Originally posted by Lee Bergeron View PostThank 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).
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.It's a pretty day. I hope you enjoy it.
Gösta
My Ego Site: http://www.SwedesDock.comPB Newby Tips: http://www.swedesdock.com/powerbasic/pb_shortcuts.htmlJWAM: (Quit Smoking): http://www.SwedesDock.com/smokingLDN - A Miracle Drug: http://www.SwedesDock.com/LDN/
Comment
-
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
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Comment
-
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 thing
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.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
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.
Comment
-
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.
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
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.
Comment
-
Personally until my post back at #15Yesterday, 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"Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Comment
Comment