I learned to code in OO languages. I’ve always been interested in design patterns, clean code, etc., etc. – you know the type.
Now at work I’m using a BASIC dialect. Given modern programming values, should we try to carry over these same principles to new procedural code?
I’m pondering the following issues, and I wondering if I’m on the right lines.
Variable Names
Variables are not strongly typed (nightmare!), they’re given short names and written in ALL CAPS (why?!) – basically I find them hard to read and they could be anything. Once upon a time, I’m sure XCNT = 1
would have offered performance gains over int_EXISTINGCUSTOMERCOUNT = 1
, but we’re past that now – surely? I choose the verbose name here.
GOSUB
I want to break down long blocks of code down into multiple smaller blocks. Internally, GOSUB
is used (over a FUNCTION
) if the helper is not re-usable by other programs / functions. Given its ability to add / modify variables without the safety of scoping (as we know it in the OO world) GOSUB
scares me.
This is typical:
GOSUB GET_BEST_CUSTOMER
IF RC = 0 THEN CRT CNAME
But I would write:
rc_GETBESTCUSTOMER = 1 ; !Default exception
str_CUSTOMERNAME = ""
GOSUB GET_BEST_CUSTOMER ; !set rc_GETBESTCUSTOMER, populate str_CUSTOMERNAME
IF(rc_GETBESTCUSTOMER = 0) THEN
CRT str_CUSTOMERNAME
END
With the caveat that GET_BEST_CUSTOMER
would only modify rc_GETBESTCUSTOMER
and str_CUSTOMERNAME
in ‘global’ scope.
There’s more, but it’s all along the same lines. Given the editor of choice (Notepad++), I’d say my coding style makes the code easier to read and understand – therefore easier to maintain. But I’m sure some BASIC die-hard would readily tell me I’m doing it all wrong.
7
GOSUB
GOSUB was a more disciplined version of GOTO. This is a particularly horrible example of the sort of misuse of GOTO that was once popular. GOSUB is an enormous step up from that, and it looks like your codebase is using labels instead of line numbers for the GOSUB targets, so it really could be a lot worse.
I don’t know what dialect of BASIC you’re using, and I hadn’t ever used FUNCTION in the little bit of BASIC programming I did a long time ago, but if FUNCTION in your dialect of BASIC is anything like a modern language function call, I’d prefer it over GOSUB for new code. In your example code, the proposed replacement was 3 times longer than the 2 line original, so I can’t really agree that it’s more readable, but I’m guessing that a rewrite of the original using FUNCTION would end up having about the same length and clarity as the original.
Naming
I don’t see the point in attaching the type to the front of the variable name. Your long names are an improvement over XCNT
, but EXISTING_CUSTOMER_COUNT
is more readable (IMO) than running them together and sticking a type prefix on it. You may be running them together due to being used to camelCase, but you can’t do camel case in all caps.
1
Variable Names
It wasn’t about performance, it was about the system only being able to interpret values with a character length less than some value (8 in most cases). Yes, verbose variable names are now allowed throughout, and use them to your heart’s content, but if you get legacy code don’t go changing variable names just because you don’t like it (as per good coding practice should say anyway). As well, all caps was used since some systems may not necessarily been on ascii standard, nor would some systems output the same print style to the screen, caps is an easy way to solve this since they should all be nearly similar.
GoSub
If you can’t protect with scoping, protect with naming. Each subroutine name should be short, that way if you do have to worry about “scoping” variables, you can append the subroutine name to the front or back of the variable, handle being descriptive about the subroutine in the comments, not the name.
Honestly, there’s not a major paradigm shift from OOP to Procedural, yes there are some semantic issues, but subroutines are key in keeping your code maintainable and semi-modular, just like classes and methods are there for that same purpose in OOP.
And as always, stay away from GOTO (Dijkstra).
2
The UniBASIC 9.3 reference manual states a 32 character limit for variable names. Iff the LONGVARS
option is active, otherwise it’s max two characters per variable name.
Names are case insensitive. Foo
, FOO
, foo
, fOo
, … are all the same name. Using all upper case is a tradition from times where machines/systems existed that only had one case for characters and that was usually upper case.
What do you mean by variables not being strongly typed? They are either a number, or a string when the name ends with $
.
I didn’t find a FUNCTION
keyword in the documentation so GOSUB
is the way to write subroutines. Then there is CALL
and ENTER
for subprograms. The only way to define functions is DEF FN
which limits function names to one letter and the implementation to one expression.
Naming the return value after the subroutine name is wasting variables. Yes, the number of variables per program also has a limit. Default is 348 names, but this can be increased via the MAXVARS environment variable. The documentation suggests the default was as low as 93 in the past.