These are all valid points, but there are counter arguments.
PB already looks strange to anyone, like myself, who has used BASIC for a long time. Besides, PB does not have a Do/Loop construct, so combining a While/Wend and Do/Loop into a While/Loop isn't going to confuse people too much.
Macros are part of the PB instruction set, so in using them there's always the risk of future name conflicts. But as with life in general, programming languages change, and like the Borg we have to adapt.
Our programs have evolved over the years, and during that time I have implemented very strict coding standards. The aim being to create bug free code that is easy to maintain, while at the same time being able to take advantage of new programming techniques.
The following code snippet may not look much like PB code, but everything about it is pure PB. It's a method from one of our code generator classes. Like all our code it makes use of macros to force rigid coding standards, make the code easy to read, and hide some of the quirky features of the PB language.
Code: Select all
;
;-----------------------------------------------
;
PrivateSubroutine(DDMod, MethodBody) (ByVal(Me, strDDMod))
;
; MethodBody generate a method
;
;
;--} local data
Local(sDataParmType, typString) ; 15080 : parameter data type
Local(sWork1, typString) ; 15084 : string work area
Local(sWork2, typString) ; 15085 : string work area
Local(sWork3, typString) ; 15086 : string work area
Local(sDataFuncType, typString) ; 15485 : function data type
;--} local code
;
; private file records on entry:
;
; Me\prrR231 - modules
; Me\prrR227 - module procedures
;
; other private file records used:
;
; Me\prrR354 - module procedure parms
; Me\prrR233 - elements
;
; local file records used:
;
; none
;
ObjectCall(gloDD, Txt1) (";")
ObjectCall(gloDD, Txt1) (#sK_1)
ObjectCall(gloDD, Txt1) (";")
sWork2 = "ByVal(Me, str{prefix})"
ObjectCall(Me\proF354, Empty) (Me\pruH354, Me\prrR354) ; module procedure parms
Me\prrR354\nModuleKey = Me\prrR227\nModuleKey
Me\prrR354\nModuleProcKey = Me\prrR227\nModuleProcKey
ObjectCall(Me\proF354, First) (Me\pruH354, Me\prrR354, #iINDEX_1, #iPARTIAL_KEY_2)
While Me\pruH354\iReturn = #iRETURN_OK
ObjectCall(Me\proF233, Empty) (Me\pruH233, Me\prrR233) ; elements
Me\prrR233\nElementKey = Me\prrR354\nElementNumber
ObjectCall(Me\proF233, Read) (Me\pruH233, Me\prrR233, #iINDEX_1)
sDataParmType = ObjectReturn(gloDD, GetDataParmType) (Me\prrR233\nElementKey)
Select Me\prrR233\cDataType
Case #cDATA_TYPE_STRUCTURE, #cDATA_TYPE_OBJECT, #cDATA_TYPE_UDT
sWork1 = "ByRef(br"
CaseElse
sWork1 = "ByVal(bv"
EndSelect
sWork2 = sWork2 + ", " + sWork1 + Me\prrR233\cDataType + Me\prrR233\sElementName + ", " + sDataParmType + ")"
ObjectCall(Me\proF354, Next) (Me\pruH354, Me\prrR354, #iINDEX_1, #iPARTIAL_KEY_2)
Loop
If Me\prrR227\cProcedureType = #sCODE_PROC_FUNCTION
sDataFuncType = ObjectReturn(gloDD, GetDataFuncType) (Me\prrR227\cDataType)
If Me\prrR227\cProcedureScope = #sCODE_SCOPE_EXTERNAL
ObjectCall(gloDD, Txt2) ("ExternalFunction({prefix}, " + Me\prrR227\sProcedureName + ", " + sDataFuncType + ")", "(" + sWork2 + ")")
Else
ObjectCall(gloDD, Txt2) ("PrivateFunction({prefix}, " + Me\prrR227\sProcedureName + ", " + sDataFuncType + ")", "(" + sWork2 + ")")
EndIf
Else
If Me\prrR227\cProcedureScope = #sCODE_SCOPE_EXTERNAL
ObjectCall(gloDD, Txt2) ("ExternalSubroutine({prefix}, " + Me\prrR227\sProcedureName + ")", "(" + sWork2 + ")")
Else
ObjectCall(gloDD, Txt2) ("PrivateSubroutine({prefix}, " + Me\prrR227\sProcedureName + ")", "(" + sWork2 + ")")
EndIf
EndIf
ObjectCall(gloDD, Txt1) (";")
ObjectCall(gloDD, Txt2) ("; " + Me\prrR227\sProcedureName, Me\prrR227\sProcedureNote)
ObjectCall(gloDD, Txt1) (";")
ClassCall(DDMod, ParmComments) (Me)
ObjectCall(gloDD, Txt1) (";")
ObjectCall(gloDD, Txt1) (";--} local data")
ObjectCall(gloDD, Txt0) ()
ClassCall(DDMod, MethodVariables) (Me)
ObjectCall(gloDD, Txt0) ()
ObjectCall(gloDD, Txt1) (";--} local code")
Select Me\prrR227\sProcedureName
Case "Constructor"
ClassCall(DDMod, CreateAutoConstructor) (Me)
Case "Destructor"
ClassCall(DDMod, CreateAutoDestructor) (Me)
CaseElse
ClassCall(DDMod, MethodCode) (Me)
EndSelect
If Me\prrR227\cProcedureType = #sCODE_PROC_FUNCTION
ObjectCall(gloDD, Txt1) ("EndFunction")
Else
ObjectCall(gloDD, Txt1) ("EndSubroutine")
EndIf
EndSubroutine
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan