Posts: 3,980
Threads: 177
Joined: Apr 2022
Reputation:
220
(06-02-2023, 09:33 PM)Dimster Wrote: Quote:and ironically Option _Explicit makes no difference in the example Dimster gave us
Not sure what you mean B .... The example with NO Option _Explicit runs fine with no error, but if you place Option _Explicit at the beginning of that code you get an error warning of an undefined variable.
...
Really, this runs fine for you???
Code: (Select All) Const i = 1
for i = 1 to 10
print i
next
Let me know what version QB64 you have LOL ;-))
I was just commenting on Terry's preaching of Option _Explicit, yes it is good but this case of yours Dimster is not helped by Option _Explicit. You do Dim the variable in a way with a Const declaration, Option _Explicit won't call you out for using Const instead of Dim.
Again Terry's preaching is in no way wrong, and great to advocate Option _Explicit usage!
b = b + ...
Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
Sorry if I sounded preachy, didn't mean to. Since I run the tutorial I gets lots of questions and requests for help behind the scenes. It's sometimes near impossible to help because of sudden variable (and "magic number", another issue entirely) creation. Declaring everything in my opinion really does help.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 3,980
Threads: 177
Joined: Apr 2022
Reputation:
220
Hey Terry I am just using "preachy" to be dramatic but yes what is more evil waste of time than a typo!
b = b + ...
Posts: 383
Threads: 56
Joined: Apr 2022
Reputation:
13
1st I apologize to NasaCow, hope the discussion on Option _Explicit may help with the search for/correction of the error you were looking for help on.
2nd ... the issue/learning lesson, for me in this thread is Dimensioned variables v's UnDimensioned variables. In particular a control variable. I have often seen the use of "i" or "j" or "x" being used in many books on Qbasic where these control variables are not Dimmed. They appear to be throw away variables in terms of their use is not material to math formulas or capture of a results of a process. They can be used over and over again as a control variable because their type is defined by default and their value is clearly defined in a range (ie 1 to 10). The only time I will Dim a control variable like "x" is if I need it to carry over into a subroutine or back to the main module.
The Dimming of a control variable, in my experience just added to multiple lines of Dim and Dim Shared in a large program. Plus it doesn't help with the ending value , or limiting the control range. For example
Code: (Select All) Dim Shared y(1 To 10)
Dim x
For x = 1 To 10
Print "Hello World"
Next
Print
Print x
Print
Print
For y = 1 To 10
Print "Hello back at ya"
Next
Print
Print y
In each case x and y finished outside of the control range, so I have to be careful when I do Dim x or y to use in another sub or function.
Not sure I see the value in Option _Explicit for control variables, nor how Dimensioning all control variables is a "Best Practice" but this old dog is definitely learning new tricks by trial and error especially when some masterfully programmers are highlighting the new trick.
Posts: 2,700
Threads: 327
Joined: Apr 2022
Reputation:
217
@Dimster Where Option _Explicit really shines is when you make a simple typo in your 10,000+ lines of code.
Let's say we have a variable like so:
DIM cheetos AS _Byte
Now, we write a line of code like so:
cheetos = (cheotes + 1) Mod 2
Now, is the syntax checker going to find anything wrong with that line of code?
NOPE! It's perfectly valid code!
Are YOU going to be able to see that you misspelled that word at 2AM in the morning, when you finally compile it and start getting unexpected results from the program? Or is your poor eyes going to just glaze over it as you scan your code and look for mistakes, skipping line 9213 repeatedly as your scroll from lines 1 to 11423 looking for a glitch??
A lot of times, the answer is: NOPE!! <--This is one of the most common type programmer errors, and one of the hardest to self-diagnose and correct. We *KNOW* what should be correct. Our brains tells us what should be correct. And our eyes just glaze over when skimming and assume that we're correct -- even if we're not.
Option _Explicit would save you a lot of hair pulling and frustration in this instance. The moment you type CHEOTES instead of CHEETOS, it'll scream at you: RAHHR!!! YOU NEVER DEFINED THAT VARIABLE!! BAD BOY!! BAD, BAD BOY!!! RAHHHHHRRRRRRR!!!!
Well... It might be a little more polite than that -- I wouldn't know, as I'm always a perfect coder and never make such mistakes and as such never have to use Option _Explicit to find any glitches in my perfect code.
Posts: 383
Threads: 56
Joined: Apr 2022
Reputation:
13
Hi Steve - I do see the value in Option _Explicit catching those misspelled variables, however my control variables (x,y,i etc) are difficult to misspell. Terry has an interesting approach to nomenclature of variables and as B and you have pointed out, you guys use it all the time. So I'm guessing here you have specific control variables which you use all the time solely for loop/iterations? You would need a least two for sort routines and perhaps a 3rd as a backup. These 3 or so control variables would be Dimensioned when? On the fly as you need them or because you know they will probably be needed some time, they are Dimensioned as a routine course after Option _Explicit?
Posts: 1,002
Threads: 50
Joined: May 2022
Reputation:
27
That reminds me of an error that apparently occurred quite often in the days of 8 and 16 bit computers (from Code Complete First Edition): The programmer didn't take into account that the result of a calculation no longer fits into the relevant variable.
The program works correctly as long as the sum stays within the bounds of an integer. A nice logical mistake!
Code: (Select All) 'Beispiel fuer Ueberlauf - 3. Juni 2023
Option _Explicit
Dim As Integer wert1, wert2, ergebnis
Locate 2, 2
Print "Example for an overflow"
Locate 4, 2
Input "Number between 1 to 32768: ", wert1
Locate 5, 2
Input "Number between 1 to 32768: ", wert2
ergebnis = wert1 + wert2
Locate CsrLin + 2, 2
Print Using "Das Ergebnis = ###,###"; ergebnis
End
Code Complete 2 (Github)
Code Complete 2
And the First Edition (Book), in English:
Code Complete First Edition
Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
(06-03-2023, 03:10 PM)Dimster Wrote: Hi Steve - I do see the value in Option _Explicit catching those misspelled variables, however my control variables (x,y,i etc) are difficult to misspell. Terry has an interesting approach to nomenclature of variables and as B and you have pointed out, you guys use it all the time. So I'm guessing here you have specific control variables which you use all the time solely for loop/iterations? You would need a least two for sort routines and perhaps a 3rd as a backup. These 3 or so control variables would be Dimensioned when? On the fly as you need them or because you know they will probably be needed some time, they are Dimensioned as a routine course after Option _Explicit?
Steve highlighted the perfect example for the use case of OPTION _EXPLICIT. Having to DIM all variables is not a negative side effect of using it. Here is an example I coded in the last half hour. Both of these code listings do the exact same thing. The first example is reminiscent of what was found in those early BASIC books. The second example is what can be done using QB64 and a bit of variable planning. Imagine being handed the first example and your task is either to find a bug or modify the code in some significant way. Now you're handed the second listing and given the same task. Which would you prefer?
Code: (Select All) 'My cool program
DIM x(59)
DIM y(59)
r = 120
FOR i = 0 TO 6.178465447 STEP .104719753
x(s) = COS(i - 1.5707963) * r + 320
y(s) = SIN(i - 1.5707963) * r + 240
s = s + 1
NEXT i
SCREEN _NEWIMAGE(640, 480, 32)
DO
CLS
_LIMIT 60
ps = s
s = VAL(RIGHT$(TIME$, 2))
IF ps <> s THEN
s6 = 0
ELSE
s6 = s6 + 1
END IF
CIRCLE (x(s6), y(s6)), 10
PAINT (x(s6), y(s6))
CIRCLE (x(s), y(s)), 10, _RGB32(255, 255, 254)
PAINT (x(s), y(s)), _RGB32(255, 255, 254), _RGB32(255, 255, 254)
_DISPLAY
LOOP UNTIL _KEYDOWN(27)
SYSTEM
Code: (Select All) ' 60th of a second sweeping clock
' Circles sweep around a clock face at 1 second and 60th second intervals
OPTION _EXPLICIT ' force variable declaration
CONST PI = 3.1415926 ' value of PI
CONST PI2 = 2 * PI ' 2 times PI (one full radian sweep)
CONST Radian60 = PI2 / 60 ' 2 times PI divided by 60
CONST Radian4 = PI2 / 4 ' one quarter of the value of PI times 2
CONST SWIDTH = 640 ' screen width
CONST SHEIGHT = 480 ' screen height
CONST CCOLOR = _RGB32(255, 255, 254) ' one second sweep circle color
TYPE Tick_Coordinate ' location of each clock tick coordinate
x AS SINGLE ' x coordinate
y AS SINGLE ' y coordinate
END TYPE
DIM Tick(59) AS Tick_Coordinate ' tick coordinates
DIM Radian AS SINGLE ' loop counter
DIM Radius AS INTEGER ' radius of clock face
DIM Second AS INTEGER ' counter: one second
DIM Second60 AS INTEGER ' counter: 60th of a second
DIM pSecond AS INTEGER ' previous second
Radius = SHEIGHT / 4 ' calculate clock face radius
Second = 0 ' reset second counter
FOR Radian = 0 TO PI2 - Radian60 STEP Radian60 ' cycle through 60 radian points
Tick(Second).x = COS(Radian - Radian4) * Radius + SWIDTH / 2 ' calculate x coordinate
Tick(Second).y = SIN(Radian - Radian4) * Radius + SHEIGHT / 2 ' calculate y coodinate
Second = Second + 1 ' increment second counter
NEXT Radian
SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32) ' graphics screen
DO ' begin main loop
CLS ' clear screen
_LIMIT 60 ' update frame every 60th of a second
pSecond = Second ' save previous second
Second = VAL(RIGHT$(TIME$, 2)) ' get current second
IF pSecond <> Second THEN ' has a second elapsed? <-- These lines synch the 60th
Second60 = 0 ' yes, reset 60th second timer <-- second circle to the top
ELSE ' no, still within same second <-- of the sweep during second
Second60 = Second60 + 1 ' increment 60th second counter <-- value changes.
END IF
CIRCLE (Tick(Second60).x, Tick(Second60).y), 10 ' draw 60th second sweep
PAINT (Tick(Second60).x, Tick(Second60).y)
CIRCLE (Tick(Second).x, Tick(Second).y), 10, CCOLOR ' draw one second sweep
PAINT (Tick(Second).x, Tick(Second).y), CCOLOR, CCOLOR
_DISPLAY ' update screen
LOOP UNTIL _KEYDOWN(27) ' leave when ESC pressed
SYSTEM ' return to operating system
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 76
Threads: 19
Joined: Apr 2022
Reputation:
5
I leave for one day and y'all go down a rabbit hole.... Great read. I will have to play more with the EXIT in something simplier before I try to start inserting it into my main project. $NOPREFIX and OPTION EXPLICIT are my first two lines whenever I start a new program for lots of reason discussed. Not only it helps prevent silly errors but keeps from being lazy with my DIM statements.
(06-02-2023, 03:14 PM)bplus Wrote: @NasaCow Search can't find ON EXIT anywhere in your code you posted.
This is what I do find:
Code: (Select All) 'Disabling the default exit routinue
ExitFlag = EXIT
ON TIMER(1) GOSUB ShutDown
TIMER ON
Code: (Select All) ShutDown:
ExitFlag = EXIT
IF ExitFlag THEN SYSTEM
RETURN
Does not look good to set ExitFlag Twice nor putting Shutdown on Timer.
When you know the user wants to quit from _Exit then you run the save work code if not saved and quit or just quit if work already saved.
I don't see need for Timer sub here.
This is the example in the Wiki more or less, and where I decided to start to try to learn something new. This the example code for _EXIT (function) - https://qb64phoenix.com/qb64wiki/index.p...(function)
You can see On Exit it isn't used here either but checks every 5 seconds with ON TIMER. The first ExitFlag is used to disable the X and setup the check with the timer. Then we evaluate it every so oftern. I will have to play with ON EXIT and see if I can get that to work (on first try, it was a no go so...)
Code: (Select All) q = _EXIT 'function read prevents any program exit at start of program
ON TIMER(5) GOSUB quit
TIMER ON
PRINT " The Timer will check for exit request every 5 seconds."
PRINT "Click the X box and/or Ctrl - Break to see the _EXIT return!"
PRINT " Any Key Quits"
PRINT
DO: _LIMIT 30
' ' simulated program loop
LOOP UNTIL INKEY$ <> ""
END
quit:
q = _EXIT
IF q THEN PRINT q;
SELECT CASE q
CASE 1: PRINT "= X button was clicked"
CASE 2: PRINT "= Ctrl + Break keypress"
CASE 3: PRINT "= Both X and Ctrl + Break!"
END SELECT
RETURN
I am all for doing it a different way, just don't know how to go about it since I never tried to control how a program closes before.
Thank you for remembering about me and I don't mind a discussion goes off track as well as helps. I ALWAYS use Option _Explicit in all my programs for that reason alone. I find it lazy programing to not DIM what you need. It makes it so much easier for other people to read the code and know what's going on. Personally, I DIM my throw away variables and give them a name like Counter or CounterX or CounterY, I just find it easy for coding when everything is named in such a way that when I come back a few months later, I still can understand it.
(06-03-2023, 01:29 PM)Dimster Wrote: 1st I apologize to NasaCow, hope the discussion on Option _Explicit may help with the search for/correction of the error you were looking for help on.
2nd ... the issue/learning lesson, for me in this thread is Dimensioned variables v's UnDimensioned variables. In particular a control variable. I have often seen the use of "i" or "j" or "x" being used in many books on Qbasic where these control variables are not Dimmed. They appear to be throw away variables in terms of their use is not material to math formulas or capture of a results of a process. They can be used over and over again as a control variable because their type is defined by default and their value is clearly defined in a range (ie 1 to 10). The only time I will Dim a control variable like "x" is if I need it to carry over into a subroutine or back to the main module.
The Dimming of a control variable, in my experience just added to multiple lines of Dim and Dim Shared in a large program. Plus it doesn't help with the ending value , or limiting the control range. For example
Code: (Select All) Dim Shared y(1 To 10)
Dim x
For x = 1 To 10
Print "Hello World"
Next
Print
Print x
Print
Print
For y = 1 To 10
Print "Hello back at ya"
Next
Print
Print y
In each case x and y finished outside of the control range, so I have to be careful when I do Dim x or y to use in another sub or function.
Not sure I see the value in Option _Explicit for control variables, nor how Dimensioning all control variables is a "Best Practice" but this old dog is definitely learning new tricks by trial and error especially when some masterfully programmers are highlighting the new trick.
Thanks for all the suggestions and this became an interesting thread in general!
WHILE NOT EndOfLife(1)
HappyLife = HappyWife - (Money * Time * Travel * Gifts)
Kids = (NoTime * LackOfLove) MOD NumOfKids
IF Retirement <> Rich THEN YearsOnJob = YearsOnJob + 1 ELSE SeeTheWorld
WEND
Posts: 3,980
Threads: 177
Joined: Apr 2022
Reputation:
220
06-04-2023, 03:20 PM
(This post was last modified: 06-04-2023, 04:10 PM by bplus.)
@NasaCow
A timer is not needed nor desired! with _Exit checking.
I am pretty sure you have a main menu loop in your program so here is how to check if user pressed an exit sequence or the very common alternate, the escape key:
Code: (Select All) Dim Shared As Long Saved ' variable that tracks work has been saved
' loadWork
' Saved = -1 ' you are saved right after you load the work data into arrays
' once exit has been called you can't use top right x to quit
' put checkQuitSave in Main loop of your program
Do ' run main menu of program here
' show menu
' catch user choice
' do it
' return to menu
Saved = 0 ' signal we made a change to work we want saved
' just to test code to see
i = i + 1
Print i
checkQuitSave
_Limit 30 ' slow down print numbers
Loop Until _KeyDown(27) ' escape
If Saved = 0 Then SaveWork ' because escape key does not run through checkQuitSave
Print "Goodbye zzz... press any to end" ' signal ending of program
Sleep
End
End
Sub SaveWork
' put everything you need to save users work here
Print "Work has been saved, zzz... press any to continue"
Sleep
Saved = -1 ' last line
End Sub
Sub checkQuitSave ' does the user wants to quit
If _Exit Then ' only when user is tryying to quit with top right click or Ctrl+break whatever break key is stops alt + F4 too
If Saved = 0 Then
SaveWork
Print "Goodbye zzz... press any to end" ' signal ending of program
Sleep
End
End If
End If
End Sub
Of course you don't have to signal user the work is saved or you could use a message box. This is just roughed out way to use _Exit.
Notice at end, while sleeping the top right X box does not work because _Exit is still forcing a coded exit method, in this case any keypress after Sleep.
b = b + ...
|