True BASIC

True BASIC was one of the first languages that I learned in school. True BASIC, isn't an extremely powerful language or with many applications, but it is a language that is effective in teaching some of the basics of programming to new students. Eventually students will move onto different languages. I've decided to open source all of my programs to reflect on some of the good and bad things about the source code I've written, and how I've changed as a developer since then.

Let's go through an example of a program I wrote then and check out what things I did well, and things that I would change now as a developer.

!__________________________________________________________
!
! Program Written by John Mercouris
!__________________________________________________________
!
! This program organizes a garage sale and keeps track
! of what items have been sold and which items are still
! for sale.
!__________________________________________________________
!
! Variables Used:
!
! StockNumber(): Stock Number of a product.
! Itemname$ (): Name of item
! Price (): Price of object
! Ifsold() (): Array denoting if an item has been sold
!__________________________________________________________
!
! Sub Programs
!
! SellstockNumber: Sell an item by stock number by calling sub
! SellName : Sell an item by name by callin sub
! SearchByName : Search for an item by name with this sub
! ItemsSold : A printout of all items sold and revenue generated
! ItemsNotSold : All items not sold , but values of items printed
!__________________________________________________________

To begin with, the header is extremely informative, but perhaps too much so. Many IDEs and #def blocks automatically create a listing of methods available in a file (think Eclipse outline view). In a lower level language or with an unsophisticated IDE/text editor, this is crucial to browsing files.

Also very important is the Variables Used section. While it shouldn't be called variables used, your declaration of your class level variables should almost always occur at the top of the file. When confusing or non-obvious variables should be commented or renamed.

CLEAR
DIM StockNumber(10000), ItemName$(10000), Price(10000), IfSold(100000)

DO While More Data
 LET X = X + 1
 READ ItemName$(x), StockNumber(x), Price(x), IfSold(x)
LOOP

CALL ShellSort (ItemName$(), StockNumber(), Price(),x, IfSold())

When writing a program with assumptions, those assumptions should be clarified in comments. For example, in this case, why is there a shell sort being called on the stock items? Does the program rely on the items being sorted? Is this useful for the user or the managing data structure?

DO while choice <> 6

 CALL Menu
 PRINT
 INPUT Prompt "Enter a choice from the menu above using it's number denotation.":Choice

 SELECT CASE Choice

 CASE is = 1
 CALL SellStockNumber (ItemName$(), StockNumber(), Price(),x, IfSold())
 CASE is = 2
 CALL SellName (ItemName$(), StockNumber(), Price(),x, IfSold())
 CASE is = 3
 CALL SearchByName (ItemName$(), StockNumber(), Price(),x, IfSold())
 CASE is = 4
 CALL ITEMSSOLD (ItemName$(), StockNumber(), Price(),x, IfSold())
 CASE is = 5
 CALL ItemsNotSold (ItemName$(), StockNumber(), Price(),x, IfSold())
 CASE is = 6

 CASE else
 END SELECT

LOOP

The above is a good usage of a main loop within a program. All of the menu subroutines are broken up into separate callbacks. This makes the code easily editable and extensible.

!__________________________________________________________
! Stock Numbers
!_________________
!
! John - 1000
! Andrew - 2000
! Theodosia - 3000
! Takis - 4000
!__________________________________________________________
! Item Name Stock Number Price IfSold
!__________________________________________________________

DATA Go Cart, 1001, 800, 0
DATA R/C Airplane, 1002, 200, 0
DATA Dell 273 A, 1003, 600, 0
DATA Projector, 1004, 400, 0
DATA Motherboard, 1006, 25, 0
DATA PS2, 1005, 80, 0
DATA Paintball Gun, 2001, 300, 0
DATA Dino GT Trick Bike, 2002, 100, 0
DATA Coffee Pot, 3001, 20, 0
DATA Necklace, 3002, 80, 0
DATA Gateway 2000, 3003, 5, 0
DATA LG Computer, 3004, 300, 0
DATA Micron Computer, 4001, 10, 0
DATA Bicycle, 4002, 40, 0
DATA CRT Tv, 4003, 300, 0

END

The above is an example of bad programming. Naming things with constants as data tags embedded in the program is not a good idea. While it is more complex to load your data from a database or a text file it is much more safe. A careless edit from a developer can result in data being lost. In addition it doesn't afford flexibility when changing back and forth from different change sets. It may be that you have to roll back your software but in doing so you lose all of your "data" that you embedded into your program. Unfortunately the above example cannot be easily remedied due to the constraints of programming in True BASIC

!______________________________________________________________________________
!
! Shell Sort
!______________________________________________________________________________

SUB ShellSort (ItemName$(), StockNumber(), Price(),x, IfSold())

 LET Gap = INT(X / 2)
 DO While Gap <> 0
 LET Flag = 1

 FOR Count = 1 to (X - Gap)

 IF ItemName$(Count) > ItemName$(Count + Gap) THEN

 LET Temp$ = ItemName$(Count)
 LET ItemName$(count) = ItemName$(count + gap)
 LET ItemName$(count + gap) = Temp$

 LET Temp = StockNumber(Count)
 LET StockNumber(count) = StockNumber(count + gap)
 LET StockNumber(count + gap) = Temp

 LET Temp = Price(Count)
 LET Price(count) = Price(count + gap)
 LET Price(count + gap) = Temp

 LET Temp = IfSold(Count)
 LET IfSold(count) = IfSold(count + gap)
 LET IfSold(count + gap) = Temp

 LET Flag = 0
 END IF

 NEXT Count
 IF Flag = 1 Then
 LET Gap = INT(Gap / 2)
 END IF
 LOOP


END SUB

When possible, always group together functionally related sections of your program. In this case, shell sort is not strongly tied to my garage sale program. Sorting is a abstract/general function that I need my program to be able to do. It would be ideal to break this apart into another file and use it as part of a library.

!______________________________________________________________________________
!
! Menu
!______________________________________________________________________________


SUB Menu

 CLEAR
 PRINT "__________________________________________"
 PRINT "| Garage Sale Menu |"
 PRINT "|________________________________________|"
 PRINT "| 1. Sell an item with stocknumber. |"
 PRINT "| 2. Sell an item by name. |"
 PRINT "| 3. Search for an item. |"
 PRINT "| 4. Items sold and profit made. |"
 PRINT "| 5. Items not sold. |"
 PRINT "| 6. Quit |"
 PRINT "|________________________________________|"

END SUB

!______________________________________________________________________________
!
! Sell by stock number
!______________________________________________________________________________


SUB SellStockNumber (ItemName$(), StockNumber(), Price(),x, IfSold())
 CLEAR
 PRINT "___________________________________________________________"
 PRINT "|Items left to sell |"
 PRINT "|_________________________________________________________|"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"
 FOR Z = 1 to X
 IF IfSold(Z) = 0 Then
 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Z), StockNumber(Z), Price(Z)
 PRINT "|_________________________________________________________|"
 END IF
 NEXT Z
 PRINT "|_________________________________________________________|"
 PRINT
 INPUT Prompt "Enter the Stock Number of the item you wish to sell, or type N to cancel.":Search


 LET Low = 1
 LET Middle = 1
 LET High = x
 DO while Search <> StockNumber(Middle) and Low <= High
 LET Middle = Int((Low + High)/2)
 IF Search < StockNumber(Middle) THEN
 LET High = Middle - 1
 END IF

 IF Search > StockNumber(Middle) THEN

 LET Low = MIddle + 1
 END IF
 LOOP
 IF Search = StockNumber(Middle) THEN
 CLEAR
 PRINT "___________________________________________________________"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"

 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Middle), StockNumber(Middle), Price(Middle)

 PRINT "|_________________________________________________________|"
 LET IfSold(Middle) = 1
 PRINT "Press any key to Continue."

The functionality of printing should be broken up into its own subroutine. In this case, printing is a non trivial task requiring several formatting operations to be done. It is coupled into a subroutine with unrelated logic. This makes the program bloated and difficult to edit. It would be ideal to break apart the printing into almost a separate file. The separate file would have an abstract printing operating where you could print a "window" with some sort of title. Then, the variables and their labels that you would like to print. In an abstract way you could reconstruct every window in this program.

 ELSE
 CLEAR
 PRINT "No results were found for your query."
 PRINT "Press any key to continue."

 END IF

 GET KEY Pse
END SUB

!__________________________________________________________
!
! Sell by name
!__________________________________________________________

SUB SellName (ItemName$(), StockNumber(), Price(),x, IfSold())

 CLEAR
 PRINT "___________________________________________________________"
 PRINT "|Items left to sell |"
 PRINT "|_________________________________________________________|"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"
 FOR Z = 1 to X
 IF IfSold(Z) = 0 Then
 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Z), StockNumber(Z), Price(Z)
 PRINT "|_________________________________________________________|"
 END IF
 NEXT Z
 PRINT "|_________________________________________________________|"
 PRINT
 INPUT Prompt "Type the name exactly as it appears using appropriate capitals, spaces etc.":Search$


 LET Low = 1
 LET Middle = 1
 LET High = x
 DO while Search$ <> ItemName$(Middle) and Low <= High
 LET Middle = Int((Low + High)/2)
 IF Search$ < ItemName$(Middle) THEN
 LET High = Middle - 1
 END IF

 IF Search$ > ItemName$(Middle) THEN

 LET Low = Middle + 1
 END IF
 LOOP
 IF Search$ = ItemName$(Middle) THEN
 CLEAR
 PRINT "___________________________________________________________"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"

 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Middle), StockNumber(Middle), Price(Middle)

 PRINT "|_________________________________________________________|"
 LET IfSold(Middle) = 1
 PRINT "Press any key to Continue."

 ELSE
 CLEAR
 PRINT "No results were found for your query."
 PRINT "Press any key to continue."

 END IF

 GET KEY Pse


END SUB

This example is of a subroutine that is far too long. Unfortunately one of the curses of BASIC is the limit of how it can combine subroutines and files.

!______________________________________________________________________________
!
! Search By Name
!______________________________________________________________________________

SUB SearchByName (ItemName$(), StockNumber(), Price(),x, IfSold())


 CLEAR
 PRINT "___________________________________________________________"
 PRINT "|Items left to sell |"
 PRINT "|_________________________________________________________|"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"
 FOR Z = 1 to X
 IF IfSold(Z) = 0 Then
 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Z), StockNumber(Z), Price(Z)
 PRINT "|_________________________________________________________|"
 END IF
 NEXT Z
 PRINT "|_________________________________________________________|"


 INPUT Prompt "Type the name exactly, spacing every word and capitalize the first letter of every word as well: ":Search$


 LET Low = 1
 LET Middle = 1
 LET High = x
 DO while Search$ <> ItemName$(Middle) and Low <= High
 LET Middle = Int((Low + High)/2)
 IF Search$ < ItemName$(Middle) THEN
 LET High = Middle - 1
 END IF

 IF Search$ > ItemName$(Middle) THEN

 LET Low = Middle + 1
 END IF
 LOOP
 IF Search$ = ItemName$(Middle) THEN
 CLEAR
 PRINT "___________________________________________________________"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"

 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Middle), StockNumber(Middle), Price(Middle)

 PRINT "|_________________________________________________________|"
 LET IfSold(Middle) = 1


 ELSE
 CLEAR
 PRINT "No results were found for your query."
 END IF
 PRINT "Press any Key to Continue"
 GET KEY pse
END SUB

!__________________________________________________________
!
! Items Sold
!__________________________________________________________

SUB ItemsSold (ItemName$(), StockNumber(), Price(),x, IfSold())

 CLEAR
 PRINT "___________________________________________________________"
 PRINT "|Items Sold |"
 PRINT "|_________________________________________________________|"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"
 FOR Z = 1 to X
 IF IfSold(Z) = 1 Then
 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Z), StockNumber(Z), Price(Z)
 LET TotalProfit = TotalProfit + Price(Z)
 PRINT "|_________________________________________________________|"
 END IF
 NEXT Z
 PRINT "|_________________________________________________________|"
 PRINT USING "Total Profit Earned was ###,###,###.##":TotalProfit
 PRINT
 PRINT "Press any key to continue"
 GET KEY pse
END SUB

!______________________________________________________________________________
!
! Items not sold
!______________________________________________________________________________

SUB ItemsNotSold (ItemName$(), StockNumber(), Price(),x, IfSold())



 CLEAR
 PRINT "___________________________________________________________"
 PRINT "|Items left to sell |"
 PRINT "|_________________________________________________________|"
 PRINT "| Name of Item Stock Number Price |"
 PRINT "|_________________________________________________________|"
 FOR Z = 1 to X
 IF IfSold(Z) = 0 Then
 PRINT USING "| <################### ######## ###,###,###.##|":ItemName$(Z), StockNumber(Z), Price(Z)
 PRINT "|_________________________________________________________|"
 END IF
 NEXT Z
 PRINT "|_________________________________________________________|"
 PRINT
 PRINT "Press any key to continue"
 GET KEY pse
END SUB

Thanks for reading!

Source code for all BASIC programs available at:

https://bitbucket.org/jmercouris/basic