Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
DECLARE LIBRARY at the end of your code?
#1
Now, I know this might seem a little strange, but hear me out:  I think folks need to start adopting the strategy of placing DECLARE LIBRARY routines at the end of their code, rather than at the beginning of it.

Now, hold up a moment there!  Before you go saying, "Welp, Steve's finally lost his marbles, everybody's always placed those declarations at the top of their source code!", give me a chance to showcase why I'll probably be adopting this new coding style from now on:

Code: (Select All)
Print BorderWidth, TitleBarHeight


Function BorderWidth&
    $Let GLUTGET = TRUE
    BorderWidth = glutGet(506)
End Function

Function TitleBarHeight&
    $Let GLUTGET = TRUE
    TitleBarHeight = glutGet(507)
End Function

Sub ScreenMove_Middle
    'Moves to the absolute middle of the desktop, ignoring border and title, so the program window is centered without
    'taking them into consideration.
    $Let GLUTGET = TRUE
    _ScreenMove (_DesktopWidth - _Width - BorderWidth) / 2 + 1, (_DesktopHeight - _Height - BorderWidth) / 2 - TitleBarHeight + 1
End Sub

Sub ScreenMove (x, y)
    'Moves to the absolute coordinates of the desktop, ignoring border and title, so the program window is
    ' positioned with the program window at the desired position, without taking them into consideration.
    $Let GLUTGET = TRUE
    _ScreenMove x - BorderWidth, y - BorderWidth - TitleBarHeight
End Sub

$If GLUTGET = TRUE Then
    $If GLUTGET_DECLARED = UNDEFINED Then
        $Let GLUTGET_DECLARED = TRUE
        Declare Library
            Function glutGet& (ByVal what&)
        End Declare
    $End If
$End If

As you can see from the code above, I can now write my SUB and FUNCTION in such a manner that they make certain that the DECLARE LIBRARY in question is included in my source.

Now, what's the point to such tomfoolery, you ask? 

In this case, it allows me to wrap everything up nice and neat in one *.BM file.  I don't need to turn the above into two different libraries, with one just for the *.BI Declare Library.  It also allows me to write these routines and wrap them up so that I can limit which ones I require in a program.  (See the recent Github Toolbox here https://github.com/SteveMcNeill/QB64-Pho...on-Toolbox for an example of this SUB/FUNCTION inclusion/exclusion at work.) 

Now, using this style, I can include one of those routines uniquely in my code as needed, and it'll automatically add in the DECLARE with it.  And, without me manually including one of those routines which need this particular DECLARE LIBRARY, it's simply excluded and not used at all in my program, keeping EXE filesize and memory usage as small as possible for whatever app I end up building.  Smile

DECLARE LIBRARY at the end of your code, instead of at the front.  It might not be just as crazy as you'd think it is at first glance.  Wink
Reply
#2
I like this.

I've been thinking for a while now that a lesson on "best practices" would be a good addition to the tutorial. I'll need to scour this and previous forums for good little juicy tidbits like this one.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#3
You guys have to be careful. There are a couple of Freebasic programmers that have absolutely no regard for "togetherness" of main-level code, putting bits of code here and there between subprogram definitions. Then there are other people exclusively using QB64 who deeply wish they could put `DATA` statements wherever they please. "Because I could do that to UDT definition" and "Because Steve now says I could DECLARE at the end" and other excuses.
Reply
#4
(10-13-2023, 03:53 AM)TerryRitchie Wrote: I like this.

I've been thinking for a while now that a lesson on "best practices" would be a good addition to the tutorial. I'll need to scour this and previous forums for good little juicy tidbits like this one.

Hi Terry,
we (Steve, you and me) already had a "best library practice" discussin about 5yrs. ago. Here's a conclusion about all suggestions and my final thougths about it. It's the "defacto" rules I build all my libraries. Also read the following posts by Fellippe regarding OPTION _EXPLICIT.

https://qb64forum.alephc.xyz/index.php?t...39#msg4039
Reply
#5
@RhoSigma Aye, I remember all those rules which we came up with, and like you, I try to always build my libraries up to those standards.  The thing is, as time passes -- that discussion was about 5 years ago -- you sometimes pick up new tricks on how to do things.   Let me showcase a few new tricks that I've started to add to my habits for library creation:

Code: (Select All)
$IF INCLUDE_ALL = TRUE OR INCLUDE_SCREEN = TRUE OR INCLUDE_SCROLLDOWN = TRUE THEN
    $IF SCROLLDOWN_BM = UNDEFINED THEN
            $LET SCROLLDOWN_BM = TRUE
            SUB ScrollDown (ImageHandle AS LONG)
            $CHECKING:OFF
            DIM m AS _MEM
            DIM AS LONG p, w
            DIM AS STRING t
            m = _MEMIMAGE(ImageHandle)
            p = _PIXELSIZE
            IF p = 0 THEN w = _WIDTH * 2 ELSE w = _FONTHEIGHT * _WIDTH * p
            t$ = SPACE$(m.SIZE - w)
            _MEMGET m, m.OFFSET, t$
            CLS
            _MEMPUT m, m.OFFSET + w, t$
            _MEMFREE m
            $CHECKING:ON
            END SUB
    $END IF
$END IF

$IF INCLUDE_ALL = TRUE OR INCLUDE_SOUND = TRUE OR INCLUDE_SPEAK = TRUE THEN
    $IF SPEAK_BM = UNDEFINED THEN
            $LET SPEAK_BM = TRUE
        $IF WIN THEN
                SUB Speak (text AS STRING, Speaker AS INTEGER, Speed AS LONG)
                DIM AS STRING message, remove
                DIM out$
                DIM AS LONG j, i
                message = text
                'some symbols and such can't be used with Powershell like this, as they're command symbols
                'we need to strip them out of our text.  (Like apostrophes!)
                remove$ = "'" + CHR$(34) 'add to remove$ here, if more symbols need to be removed as future testing showcases problems
                FOR j = 1 TO LEN(remove$)
                DO
                i = INSTR(message, MID$(remove$, j, 1))
                IF i THEN message = LEFT$(message, i - 1) + MID$(message, i + 1)
                LOOP UNTIL i = 0
                NEXT
                out$ = "Powershell -Command " + CHR$(34)
                out$ = out$ + "Add-Type -AssemblyName System.Speech; "
                out$ = out$ + "$Speech = New-Object System.Speech.Synthesis.SpeechSynthesizer; "
                IF Speaker = 0 THEN out$ = out$ + "$Speech.SelectVoice('Microsoft David Desktop'); "
                IF Speaker = 1 THEN out$ = out$ + "$Speech.SelectVoice('Microsoft Zira Desktop'); "
                IF Speed THEN out$ = out$ + "$Speech.Rate =" + STR$(Speed) + "; "
                out$ = out$ + "$Speech.Speak('" + message + "');" + CHR$(34)
                SHELL _HIDE out$
                END SUB
        $ELSE
                Sub Speak (dummy as string, dummy1 as Integer, dummy2 as long)
                BEEP
                _MESSAGEBOX "Warning!", "Notice: SUB Speak is a Windows-Only routine, as it relies upon Powershell to do its work.  This routine does not work on Linux or Mac.", "warning"
                End Sub
        $END IF
    $END IF
$END IF

$IF INCLUDE_ALL = TRUE OR INCLUDE_SCREEN = TRUE OR INCLUDE_BORDERWIDTH = TRUE THEN
    $IF BORDERWIDTH_BM = UNDEFINED THEN
            $LET BORDERWIDTH_BM = TRUE
            FUNCTION BorderWidth&
            $LET GLUTGET = TRUE
            BorderWidth = glutGet(506)
            END FUNCTION
    $END IF
$END IF

Now, the above is from the new toolbox which I'm assembling on github.  The idea here is to allow the user the flexibility to ONLY add what routines they want into their code, to reduce size and memory usage as much as possible.

Want all three routines?   $LET INCLUDE_ALL = TRUE    <-- one line of code at the top of your program and they're all included.
Only want the two screen routines?  $LET INCLUDE_SCREEN = TRUE  <-- again, one line of code which only enables those two routines.
Only want one particular routine?  $LET INCLUDE_SPEAK = TRUE  <-- and now we're only including the powershell text-to-speech routine.

And another trick which I've learned over the last few years?
Code: (Select All)
    $IF BORDERWIDTH_BM = UNDEFINED THEN
            $LET BORDERWIDTH_BM = TRUE
            FUNCTION BorderWidth&
            $LET GLUTGET = TRUE
            BorderWidth = glutGet(506)
            END FUNCTION
    $END IF

With the above wrapped around the sub/function, it doesn't matter if multiple libraries include the routine.  It doesn't matter if it's in half a dozen $INCLUDE files.  The first one that calls it will set the precompiler flag for it, and it'll be excluded when it comes to the rest of those routines.

No more "Duplicate Definitions" or "Name already in use" or whatnot errors.

And take this practice, along with the idea of moving your DECLARE LIBRARY code to the end of your source as I suggested in the first post here, and you can easily use one library to hold a whole collection of subs and functions, and only include the specific ones you need into your program.  Just make certain that if one of the required programs uses a different routine inside the library, that it sets the independent flag to make certain that requite routine is also enabled.  (Like with the glutget routines in my first post.)

I'm *still* sticking to the old set and true rules that we invented all those years ago -- I'm just learning to expand my tricks and building upon those rules in an attempt to make my stuff both more flexible and less error prone in the future.  

Smile
Reply
#6
(10-13-2023, 08:06 AM)SMcNeill Wrote: @RhoSigma Aye, I remember all those rules which we came up with, and like you, I try to always build my libraries up to those standards.  The thing is, as time passes -- that discussion was about 5 years ago -- you sometimes pick up new tricks on how to do things.   Let me showcase a few new tricks that I've started to add to my habits for library creation:

Code: (Select All)
$IF INCLUDE_ALL = TRUE OR INCLUDE_SCREEN = TRUE OR INCLUDE_SCROLLDOWN = TRUE THEN
    $IF SCROLLDOWN_BM = UNDEFINED THEN
            $LET SCROLLDOWN_BM = TRUE
            SUB ScrollDown (ImageHandle AS LONG)
            $CHECKING:OFF
            DIM m AS _MEM
            DIM AS LONG p, w
            DIM AS STRING t
            m = _MEMIMAGE(ImageHandle)
            p = _PIXELSIZE
            IF p = 0 THEN w = _WIDTH * 2 ELSE w = _FONTHEIGHT * _WIDTH * p
            t$ = SPACE$(m.SIZE - w)
            _MEMGET m, m.OFFSET, t$
            CLS
            _MEMPUT m, m.OFFSET + w, t$
            _MEMFREE m
            $CHECKING:ON
            END SUB
    $END IF
$END IF

$IF INCLUDE_ALL = TRUE OR INCLUDE_SOUND = TRUE OR INCLUDE_SPEAK = TRUE THEN
    $IF SPEAK_BM = UNDEFINED THEN
            $LET SPEAK_BM = TRUE
        $IF WIN THEN
                SUB Speak (text AS STRING, Speaker AS INTEGER, Speed AS LONG)
                DIM AS STRING message, remove
                DIM out$
                DIM AS LONG j, i
                message = text
                'some symbols and such can't be used with Powershell like this, as they're command symbols
                'we need to strip them out of our text.  (Like apostrophes!)
                remove$ = "'" + CHR$(34) 'add to remove$ here, if more symbols need to be removed as future testing showcases problems
                FOR j = 1 TO LEN(remove$)
                DO
                i = INSTR(message, MID$(remove$, j, 1))
                IF i THEN message = LEFT$(message, i - 1) + MID$(message, i + 1)
                LOOP UNTIL i = 0
                NEXT
                out$ = "Powershell -Command " + CHR$(34)
                out$ = out$ + "Add-Type -AssemblyName System.Speech; "
                out$ = out$ + "$Speech = New-Object System.Speech.Synthesis.SpeechSynthesizer; "
                IF Speaker = 0 THEN out$ = out$ + "$Speech.SelectVoice('Microsoft David Desktop'); "
                IF Speaker = 1 THEN out$ = out$ + "$Speech.SelectVoice('Microsoft Zira Desktop'); "
                IF Speed THEN out$ = out$ + "$Speech.Rate =" + STR$(Speed) + "; "
                out$ = out$ + "$Speech.Speak('" + message + "');" + CHR$(34)
                SHELL _HIDE out$
                END SUB
        $ELSE
                Sub Speak (dummy as string, dummy1 as Integer, dummy2 as long)
                BEEP
                _MESSAGEBOX "Warning!", "Notice: SUB Speak is a Windows-Only routine, as it relies upon Powershell to do its work.  This routine does not work on Linux or Mac.", "warning"
                End Sub
        $END IF
    $END IF
$END IF

$IF INCLUDE_ALL = TRUE OR INCLUDE_SCREEN = TRUE OR INCLUDE_BORDERWIDTH = TRUE THEN
    $IF BORDERWIDTH_BM = UNDEFINED THEN
            $LET BORDERWIDTH_BM = TRUE
            FUNCTION BorderWidth&
            $LET GLUTGET = TRUE
            BorderWidth = glutGet(506)
            END FUNCTION
    $END IF
$END IF

Now, the above is from the new toolbox which I'm assembling on github.  The idea here is to allow the user the flexibility to ONLY add what routines they want into their code, to reduce size and memory usage as much as possible.

Want all three routines?   $LET INCLUDE_ALL = TRUE    <-- one line of code at the top of your program and they're all included.
Only want the two screen routines?  $LET INCLUDE_SCREEN = TRUE  <-- again, one line of code which only enables those two routines.
Only want one particular routine?  $LET INCLUDE_SPEAK = TRUE  <-- and now we're only including the powershell text-to-speech routine.

And another trick which I've learned over the last few years?
Code: (Select All)
    $IF BORDERWIDTH_BM = UNDEFINED THEN
            $LET BORDERWIDTH_BM = TRUE
            FUNCTION BorderWidth&
            $LET GLUTGET = TRUE
            BorderWidth = glutGet(506)
            END FUNCTION
    $END IF

With the above wrapped around the sub/function, it doesn't matter if multiple libraries include the routine.  It doesn't matter if it's in half a dozen $INCLUDE files.  The first one that calls it will set the precompiler flag for it, and it'll be excluded when it comes to the rest of those routines.

No more "Duplicate Definitions" or "Name already in use" or whatnot errors.

And take this practice, along with the idea of moving your DECLARE LIBRARY code to the end of your source as I suggested in the first post here, and you can easily use one library to hold a whole collection of subs and functions, and only include the specific ones you need into your program.  Just make certain that if one of the required programs uses a different routine inside the library, that it sets the independent flag to make certain that requite routine is also enabled.  (Like with the glutget routines in my first post.)

I'm *still* sticking to the old set and true rules that we invented all those years ago -- I'm just learning to expand my tricks and building upon those rules in an attempt to make my stuff both more flexible and less error prone in the future.  

Smile

No problem with all that, I like the idea with the glut stuff. I usually solved that problem by using ALIAS names, eg.

In LibOne:
DECLARE CUSTOMTYPE LIBRARY
SUB LibOne_memset ALIAS memset (BYVAL dest%&, BYVAL value&, BYVAL size&)
SUB LibOne_memcpy ALIAS memcpy (BYVAL dest%&, BYVAL sour%&, BYVAL size&)
SUB LibOne_strncpy ALIAS strncpy (BYVAL dest%&, BYVAL sour%&, BYVAL size&)
END DECLARE

In LibTwo:
DECLARE CUSTOMTYPE LIBRARY
SUB LibTwo_memset ALIAS memset (BYVAL dest%&, BYVAL value&, BYVAL size&)
SUB LibTwo_memcpy ALIAS memcpy (BYVAL dest%&, BYVAL sour%&, BYVAL size&)
SUB LibTwo_strncpy ALIAS strncpy (BYVAL dest%&, BYVAL sour%&, BYVAL size&)
END DECLARE

and then using the alias names in the respective libraries where I declared it, but finally they end up using all the same function in the linked EXE.

another thing I came up with, is to implement version strings into all my libraries and tools,
see here: https://qb64phoenix.com/forum/showthread.php?tid=2220
Reply
#7
Depending on the kind of library, I like to put the declarations at the top, if multiple functions will be pulling from the same DLL. However, if I have tons of functions and each one can be used basically independent of another, then I will put the declarations of the libraries inside the functions themselves. That way it is a simple copy and paste from `Function` to `End Function`. Otherwise, no. I'm not putting declarations at the end of my code. Ugly as Hell.

P.S.
Did y'all remove the backtick formatting?
Tread on those who tread on you

Reply
#8
(10-18-2023, 11:07 AM)SpriggsySpriggs Wrote: P.S.
Did y'all remove the backtick formatting?

Yes it's gone, caused different problems when using backticks inside of code examples, such as the _BIT type suffix or ASCII Art like stuff.

In some cases it just eat the backticks, in other cases it messed up highlighting, and in worst cases it did build nested codeboxes.
Reply




Users browsing this thread: 5 Guest(s)