gmplRefactoringStatements

gmPL Refactoring Statements

Within gmBasic many of the changes made to the code as it moves from its VB6/ASP source code form into its ultimate .NET target code form can most easily be formulated as refactoring operations. These include:
  1. Renaming symbols either to avoid clashes or to make them easier to maintain.
  2. Reauthoring a subprogram because its original approach is inappropriate or unworkable in the .NET environment
  3. Changing the type of a symbol which was either undefined or too weakly specified.
  4. Changing the status of a symbol to change its scope or behavior
  5. Changing the structure of a symbol to clarify its size and dimensionality.
  6. Removing a symbol because it is not needed or wanted.
  7. Changing logic flow and/or program operations to conform to new requirements.
  8. Replacing references to external libraries with references to native libraries
All of these operations involve manipulations of the symbol table and of the intermediate code produced. They do not directly reference the source or target code. The refactoring statements themselves are:


Statement Description of use
RefactorIntroduces a set of refactoring statements
CallByNameChanges symbol-related code events that yield CallByName late binding calls into direct boxed calls.
ExtendExtends the content of a class by adding new components.
FixTypeChanges the binary type of a component or group of components
GenericSpecifies that individual subprogram parameters be implemented as being generic to accept a list of different types.
ImplementsSpecifies that a VB6 class implements another class or interface.
MigClassIntroduces a new class that contains related refactoring information used for complex migration operations, especially as related to designer code.
MigrateSpecifies migration of a specific symbol introduced via an external library description.
OverGenericSpecifies that individual subprogram parameters be implemented as being generic in an overloaded method to accept a list of different types.
OverloadSpecifies that individual subprogram arguments be overloaded to accept a list of different types.
ReauthorReplaces the content of a subprogram with a completely rewritten block of code
RemovePrevents a component from being authored
RenameChanges the authored name of components
ReplaceReplaces either the members of an external class or the patterns of opcodes via replacement declarations.

Within gmBasic the portation process proceeds in 8 steps:
  1. Loading the VB6/ASP source code.
  2. Fixing the VB6/ASP source code.
  3. Building the symbol table from the source code
  4. Compiling the source code into intermediate code
  5. Analysing the symbol table and intermediate code
  6. Authoring the target code from the intermediate code and symbol table
  7. Fixing the target code
  8. Deploying the target code
During this process there are 3 points at which refactoring operations can be made. First after step 3, which builds the symbol table. This is a very effective place to strengthen the specifications of the symbols so that the compiler can take advantage of this additional information while generating the intermediate code. Second after step 4 when the compiler has completed, but the code analyser has not yet run. This is an excellent time to introduce .NET types explicitly and to do any removals. Third after step 5, when the analyser has run, but before the author has executed. This is the best time to do symbol renaming and code reauthoring.


Refactoring tends to effect the entire code base. It is not intended to make individual changes in actual code. The source code fixing operations are intended for this. The rule of thumb for using a refactoring operation as opposed to a fix editing operation is that the specification for the final recipient of the change is a symbol as opposed to a line/block of code. In general, portation is an art and the selection of which approach to use will clearly vary by individual and application.


Whenever possible, refactoring should be done via "shallow" changes -- changes which are applied to the actual surface or source form of the code using the Fix statement. These shallow changes can be applied to both the source code before it is translated and to the target code after it is produced, but before it is published. Such changes are easy to visualize and to specify. Unfortunately many of the changes needed cannot be specified in this way -- refactoring is required.

Refactoring Property Specifications

Many of the refactoring statements are used to deal with the transformation of the VB6 property specifications into .NET designer code. Much of the code within VB6 forms deals with controls. These controls all have complex sets of properties that must be initialized within the VB6 code. This initialization code contains nested sets of "name=value" pairs organized into nested blocks started off by BEGIN or BEGINPROPERTY statements and ending with END or ENDPROPERTY statements. Here is a simple example of such a specification.



 Begin VB.Form VB0001Form
    Caption         =   "VB0001"
    ClientHeight    =   5115
    ClientLeft      =   60
    ClientTop       =   345
    ClientWidth     =   5280
    LinkTopic       =   "Form1"
    ScaleHeight     =   5115
    ScaleWidth      =   5280
    StartUpPosition =   3  'Windows Default
    Begin VB.CommandButton Command1
       Caption         =   "Run VB0001 Test"
       Height          =   375
       Left            =   1440
       TabIndex        =   0
       Top             =   1320
       Width           =   1935
   End
 End
In the above, the Begin has the syntax "Begin controltype identifier" where controltype is a defined control type and identifier is the identifier of the control object in the user code that is being defined. In the name=value pairs the name is the name of a property defined for the control type class and the value is the value to be assigned to that property for the identified instance of the control type.


There are of course properties of controls that are themselves object types rather than simple value types. The most common of these is the Font property. Here is an example of a specification of this type.



 Begin VB.Label lblFirst
    Alignment       =   2  'Center
    BorderStyle     =   1  'Fixed Single
    Caption         =   "VB is fun"
    BeginProperty Font
       Name            =   "MS Sans Serif"
       Size            =   24
       Charset         =   0
       Weight          =   700
       Underline       =   0   'False
       Italic          =   0   'False
       Strikethrough   =   0   'False
    EndProperty
    Height          =   615
    Left            =   2040
    TabIndex        =   0
    Top             =   480
    Width           =   2655
 End
In the above the BeginProperty statement has the syntax "BeginProperty property" where property is the identifier of a property in the containing control type that has an object type. There is no additional identifier here because the values are part of the higher instance. BeginProperty is semantically equivalent to a simple name=value pair except that multiple values are being supplied.


All of the above is an oversimplification in every possible way. Even in the above "simplest of all examples", for example, the VB.Label control type does not have a property called Font; rather it has properties like FontName, FontSize etc. When the above syntax is extended to COM CONTROLS all formal relationships are ignored in every possible way. The specifications look like the above, but there truly are no real rules. Each COM property specification has to be examined carefully and converted into a specification that associates values with a set of user-defined controls in a consistent manner.


Converting the input property specifications into a consistent form is a difficult, but trivial problem when compared to the problem of reauthoring those specifications in .NET. The two primary problems are that in .NET controls are not nested, they have a linear structure and then there are later instructions that add children into the scope of the parents. How and when and with what adornments are needed to make these scope specifications vary widely. In addition in .NET some values are assigned to properties directly in the code and others are assigned via external resource files.


An important point to be remembered about the property specification code is that though it uses opcodes, though opcodes are not authored via a string-machine. It has code fragments in it that can be evaluated and viewed in the same way as procedural code, but it is used simply as a data-store for the information initially obtained from the VB6 specifications and then as changed to supply information to the .NET control author. New properties must be added, old properties must be removed or restructured or radically migrated. There are no dependable simplistic correspondences between properties defined for the classes and references to those properties. The goal is that the eventual authored .NET property specifications will accurately reflect the original intent of the VB6 source; however, that goal is achieved via the interaction of diverse components and not directly in the property code blocks.
Table of Contents