I don't claim here again showing the best pratices ever, but the topic as a whole is interesting. It could hardly be left untouched at all.
If one knows about best pratices anyway, he can just leave a useful remark around here.
(Thanks to fxm for the first recommendations that helped me reformulating the things)
Renaming - A showcase
I - Resolving conflicts
One of the interest of renaming symbols is to fix conflict when they meet together under a same identifiers.
- A - Resolving conflict with the help of namespaces blocks
- B - Resolving conflict with the help of #UNDEF
Take two source files. A main current source is modifiable. And a source file imported, via the #include instruction, has its content that must keep untouched.
case 1
we may embed the imported stuff into a namespace to distinguish conveniently its declarations from the current declarations in use.
Remark: works only if the imported source contains nothing but declarations, or functions/subroutines blocks.
Performance overhead: none known to me
Code: Select all
'file to be saved as "importedfile.bas" in the same dir as the *main file*
'we declare a variable we will conflict with:
const as integer xxx => 99
'(eof)
Code: Select all
'main code file - where the user is supposed to work currently on
'we can do this as below only if the imported file contains only declarations
'(generally the imported filename would take a terminal .bi as extension)
nameSpace importedDeclarations
#include "importedfile.bas"
end nameSpace
const as integer xxx => 44
? importedDeclarations.xxx
? xxx
getKey()
'(eof) tested on XPwin32 fb1.05
we may embed the stuff of ours, currently at work, into one or many namespaces.
Remark: A namespace can only hold declarations - in the version of FB in use here (1.05) at least - but, surprisingly enough, a same namespace can be open and closed as many times as wanted to collect declarations into it here and there many times.
Performance overhead: none known to me
Code: Select all
'main code file - where the user is supposed to work currently on
#include "importedfile.bas"
nameSpace currentDeclarations
const as integer xxx => 44
end nameSpace
? currentDeclarations.xxx
? xxx
getKey()
'(eof) tested on XPwin32 fb1.05
Code: Select all
'main code file - where the user is supposed to work currently on
#include "importedfile.bas"
nameSpace currentDeclarations
const as integer xxx => 44
end nameSpace
? currentDeclarations.xxx
? xxx
nameSpace currentDeclarations 'again!
dim as integer yyy => 88
end nameSpace
? currentDeclarations.xxx
? currentDeclarations.yyy
? xxx
getKey()
'(eof) tested on XPwin32 fb1.05
Let take again the story of our 2 source files, one 'include file' and the current work.
case 1
The idea here is to copy every duplicate into brand new variables with non-conflicting names, then, wash out the old names by an #undef, and finally, reuse the unbound names in our current work file.
Remark: the old variables will stand somewhere in memory without any way to reach them, unless we destroy them before undef, but, in the case of a constant, I don't see what this could mean... Otherwise we could also keep track of the variable content with lost identifier via a pointer to its data address in memory. But here again when the variable is a constant like in the example, what is a Const Ptr in FB?
Performance possible overhead: At least a new declaration with a copy by value initialization for each duplicate to solve out.
Code: Select all
'main work file
#include "importedfile.bas"
const xxx_ => xxx 'transfer
'note:
'I'm not sure that the datatype should not be specified in the const
#undef xxx 'undefine
const as integer xxx=> 44 'reuse
? "current xxx, xxx="; xxx
? "imported xxx, now renamed as 'xxx_', xxx_="; xxx_
'(eof) fb1.05
This is something that seems just not possible to do: undefine a user defined type identifier; even if we have taken care of renaming it before thanks to the TYPE... AS... instruction. This however only true with imported material, otherwise undef seems to work.
And unfortunately I can't see the reason for this...
Code: Select all
'file to be saved as "importedfile.bas" in the same dir as the 'main file'
'declaring a UDT we will conflict with:
type CONFLICT
as string _stringvariable => "hello"
end type
'(eof)
Code: Select all
'main work file
#include "importedfile.bas"
type CONFLICT_ as CONFLICT 'transfer
#undef CONFLICT 'error 176: This symbol cannot be undefined
type CONFLICT 'error 4: Duplicated definition, CONFLICT
as string _stringvariable => "goodbye"
end type
? "current CONFLICT udt, CONFLICT._stringvariable="; CONFLICT._stringvariable
? "imported CONFLICT, now renamed as 'CONFLICT_', CONFLICT_._stringvariable="; CONFLICT_._stringvariable
'(eof) fb1.05
II - Using an alias for reducing identifier's length
The focus here is set on renaming again, but in order to reuse symbols under shorter names than those they have been given at their creation.
Doing so, some long named stuff can have their names exchanged for small things and then can not be said to be prone to any reading/writting trouble.
- A - Reducing identifier's size with VAR BYREF <varshortname> = <varlongname>
- B - Reducing identifier's size with VAR <procshortname> = @<proclongname>
- C - Reducing identifier's size with TYPE <shortname> AS <longname>
- D - Reducing identifier's size with #DEFINE <shortname> <longname>
Consider some variable of your main source file. We'll want to add a name alias shorter than the initial name to work with very exactly as we would do with the original.
Remark: we'll have to distinguish the case of CONST.
Performance possible overhead: A declaration with a copy by reference initialization for each duplicate we create. This is about pointers so equivalent to the copy of the integer value holding the variable address independently of the datatype value size.
case 1
We will start with the case of CONST that seems not able to work as we wish without a special declination of the syntax that fortunately will make everything work equivalently.
Code: Select all
'VAR BYREF for identifier change - case of CONSTANT
const as integer veryLongName = 333 'Not OK for us
var byref shorty = veryLongName 'error 24: Invalid data types
dim byref as integer shorty = veryLongName 'error 24: Invalid data types
'(eof) fb1.05
Unfortunately we have nothing as VAR AS CONST, so a classical CONST statement not mentionning explicitly a datatype, has no direct workaround visible to me.
Code: Select all
'var byref for identifier reuse - case of CONSTANT
dim as const integer veryLongName = 333 'OK
'dim as const (typeOf(333)) veryLongName = 333 'NOK -> error 14: Expected identifier
var byref shorty = veryLongName 'OK
'dim byref as integer shorty = veryLongName 'NOK -> error 24: Invalid data types
'dim byref as integer const shorty = veryLongName 'NOK -> error 272: Expected 'PTR' or 'POINTER'
? veryLongName
? shorty
'(eof) fb1.05
A more common issue addressed here is something like in the next example where names are even more inflated due to the cascading of the dot notation.
Code: Select all
type MYVERYBELOVEDUSERDEFINEDTYPE
as integer _myAbsolutlyCherishedIntegerField
end type
type MVBUDT as MYVERYBELOVEDUSERDEFINEDTYPE
dim as MVBUDT someInstance
someInstance._myAbsolutlyCherishedIntegerField => 44
'(eof) fb1.05
Code: Select all
type MYVERYBELOVEDUSERDEFINEDTYPE
as integer_myAbsolutlyCherishedIntegerField
end type
type MVBUDT as MYVERYBELOVEDUSERDEFINEDTYPE
dim as MVBUDT someInstance
var byref i => someInstance._myAbsolutlyCherishedIntegerField
i = 44 'now i stands as an alias for the full longname above
? someInstance._myAbsolutlyCherishedIntegerField
'(eof) fb1.05
Worth some attention here: the problem with static functions.
I don't know if the compiler should not catch this in order to trigger some warning? (I love the warnings!)
Code: Select all
type X
as integer i = 999
end type
function XXX() as integer static ''static not good here!
dim as X xInstance
var byref j = xInstance.i
return j
end function
? XXX()
'(eof) fb1.05
If the purpose is to rename a function, here is a very nice FB feature, of a rare frugal and efficent syntax.
Remark: none.
Performance possible overhead: A declaration with a copy by reference initialization for each alias created this way.
Code: Select all
function XXX(byval x as integer) as double
XXX = 33
end function
var YYY => @XXX
? YYY(88)
'(eof) fb1.05
It's how to give an alias to a user defined type.
Remark: there is also the same syntax to name a UDT pointer, like for type forwarding and many other interesting bindings that unfortunately I don't master.
Performance possible overhead: I don't know what is the category of this, re-assignement, text-replacement? So I can not judge.
Code: Select all
'declare first a type
type EXAMPLEUDT
as integer _integerUdtField
end type
'trigger a type alias
type EU as EXAMPLEUDT
'now use the alias or the original name anywhere
'with only 1 condition, the type declaration must have preceded the usage
dim as EU euInstance
Indeed text replacement is the most immediate tool one can think of to handle renaming/aliasing issues.
However, in this topic I would object that the conventions I use myself to distinguish "defines" from variables or functions tend to give them a long name, all uppercase, and with a underscore as prefix (one of the goals is to make them unique so that they won't conflict if the code has to import new defines; they are prone to conflict because they are global by nature). So that this is not much suitable for code size reduction!
But #DEFINE is a great tool. And I'll give two examples.
A single "novelty" maybe: the scope emulation. Defines, at least as far as I know, aren't undefined according to common destruction rules related to local objects. So to forbid a define meant to keep localized from propagating, one must think of undefining it before the concerned scope ends.
Now from a performance point of view, it's all code preprocessing so it can not interfer by itself with the program performances. The text replacement is done before the code is compiled. Look at option -pp of the compiler to generate a snapshot of the resulting source code after the replacement is done.
Code: Select all
type MYVERYBELOVEDUSERDEFINEDTYPE
as integer _myAbsolutlyCherishedIntegerField
end type
type MVBUDT as MYVERYBELOVEDUSERDEFINEDTYPE
dim as MVBUDT someInstanceOfMvbUdt
#define _FIELD someInstanceOfMvbUdt._myAbsolutlyCherishedIntegerField
_FIELD => 44
? _FIELD
? someInstanceOfMvbUdt._myAbsolutlyCherishedIntegerField
#undef _FIELD
'(eof) fb1.05
Code: Select all
type UDTEXAMPLE
declare constructor(ArrayExtension as integer=10)
redim as integer _arrayOfInteger(0)
end type
type UE as UDTEXAMPLE
constructor UE(ArrayExtension as integer=10)
#define _A(Ax) THIS._arrayOfInteger(uBound(THIS._arrayOfInteger) + Ax)
redim preserve _A(ArrayExtension)
redim preserve _A(-ArrayExtension)
? uBound(THIS._arrayOfInteger)
#undef _A
end constructor
dim as UE ueInstance
getKey()
'(eof) fb1.05
That will be all of for today!
(...)