gmplOverloadStatement

Overload Statement Summary

Overload is a terminal, refactoring statement that occurs within Refactor statements. It is used to specify that individual subprogram parameters be overloaded to accept a list of different types.

The attributes of the Overload statement are as follows:

Attribute Description
Identifier This required attribute specifies the symbol, the actual parameter to be overloaded. If the containing Refactor statement had a FileFilter specified then this identifier should be specified relative to it; else, it should be specified relative to the root of the symbol table
Types This required attribute contains a comma-delimited list of the types to be allowed for the overloaded parameter.

The Overload statement is especially important for dealing with ByRef parameters that have Variant or Object types. Note that this statement is closely related to the Generic and OverGeneric refactoring statements which also deal with these types of parameters.

Consider the following simple VB6 code


Private Sub Form_Load()
   Dim fiveString As String
   Dim fiveNumber As Integer
   MySub False, fiveString
   MySub True, fiveNumber

   Dim sixNumber As Integer
   sixNumber = 1 + fiveNumber
   MsgBox "Five plus one is " & sixNumber

   Dim sixString As String
   sixString = "one plus " & fiveString
  MsgBox "In other words six is equal to " & sixString
End Sub

Private Sub MySub(ByVal i_Param1 As Boolean, ByRef o_Var As Variant)
   If i_Param1 Then
       o_Var = 5
   Else
       o_Var = "five"
   End If
End Sub
Though this is clearly a contrived example such uses of Variant ByRef parameters are quite common in VB6 code. The important thing to note is that the parameter returns either an integer value or a string value to an argument of the corresponding binary type. Using this default translation script


<gmBasic>
   <Storage Action="Create" Identifier="Overload" />
   <Select DevEnv="VS2013" />
   <Select Dialect="csh" />
   <Select BuildFile="local" />
   <Select DeployLocation="C:\Temp" />
   <Select System="..\..\FromIdl" />
   <Compile Project="..\vb6\Project1.vbp" >
   </Compile>
   <Analyse />
   <Output Status="New" Filename="..\csh\Overload.bnd" />
   <Author />
   <Storage Action="Close" />
</gmBasic>
produces this translation


private void Form_Load(object sender, EventArgs e)
{
   string fiveString = "";
   int fiveNumber = 0;
   int refTemp1 = Convert.ToInt32(fiveString);  <=======
   MySub(false,ref refTemp1);
   MySub(true,ref fiveNumber);

   int sixNumber = 0;
   sixNumber = 1 + fiveNumber;
   System.Windows.Forms.MessageBox.Show("Five plus one is " + sixNumber, "", MessageBoxButtons.OK);

   string sixString = "";
   sixString = "one plus " + fiveString;
  System.Windows.Forms.MessageBox.Show("In other words six is equal to " + sixString, "", MessageBoxButtons.OK);
}
private void MySub(bool i_Param1,ref int o_Var)   <======
{
   if (i_Param1)
   {
      o_Var = 5;  <======
   }
   else
   {
      o_Var = Convert.ToInt32("five");
   }
}
Since the tool has no consistent typing in the the arguments being passed to the parameter o_Var, it takes the first assignment, which is an integer assignment, and types the parameter accordingly. The consequences of this is that the string return case will either throw an exception or return zero. Regardless of this, even if a value is returned to the Form_Load method it will end up being stored in the refTemp1 variable and not in fiveString. Using a Refactor.Fixtype statement like the following


<FixType identifier="Project1.Form1.MySub.o_Var" Type="Variant" status="ObjectOnly" />
produces this improved translation of MySub


private void Form_Load(object sender, EventArgs e)
 {
   string fiveString = "";
   int fiveNumber = 0;
   object argTemp1 = fiveString;
   MySub(false,ref argTemp1);
   object argTemp2 = fiveNumber;
   MySub(true,ref argTemp2);

   int sixNumber = 0;
   sixNumber = 1 + fiveNumber;
   System.Windows.Forms.MessageBox.Show("Five plus one is " + sixNumber, "", MessageBoxButtons.OK);

   string sixString = "";
   sixString = "one plus " + fiveString;
   System.Windows.Forms.MessageBox.Show("In other words six is equal to " + sixString, "", MessageBoxButtons.OK);
}
private void MySub(bool i_Param1,ref object o_Var)
{
   if (i_Param1)
   {
      o_Var = 5;
   }
   else
   {
      o_Var = "five";
   }
}
but makes the calling code in Form_Load even worse. Now neither source argument actually ends up receiving its intended value. The Overload statement resolves this problem by treating the parameter as though it had been marked as ObjectOnly and by supplying overloaded versions of the method being called that takes ByRef String and ByRef Integer parameters. The following script uses this statement.


<gmBasic>
   <Storage Action="Create" Identifier="Overload1" />
   <Select DevEnv="VS2013" />
   <Select Dialect="csh" />
   <Select BuildFile="local" />
   <Select DeployLocation="C:\Temp" />
   <Select System="..\..\FromIdl" />
   <Compile Project="..\vb6\Project1.vbp" >
      <Refactor>
         <OverLoad identifier="Project1.Form1.MySub.o_Var" Types="Integer,String" />
      </Refactor>
   </Compile>
   <Analyse />
   <Output Status="New" Filename="..\csh\Overload1.bnd" />
   <Author />
   <Storage Action="Close" />
 </gmBasic>
In the Overload statement the Identifier attribute contains the fully qualified identifier of the parameter and the Types attribute specifies that there are to be two overloaded versions of the method using the two types specified. The resultant translation is as follows.


private void Form_Load(object sender, EventArgs e)
{
   string fiveString = "";
   int fiveNumber = 0;
   MySub(false,ref fiveString);
   MySub(true,ref fiveNumber);

   int sixNumber = 0;
   sixNumber = 1 + fiveNumber;
   System.Windows.Forms.MessageBox.Show("Five plus one is " + sixNumber, "", MessageBoxButtons.OK);

   string sixString = "";
   sixString = "one plus " + fiveString;
   System.Windows.Forms.MessageBox.Show("In other words six is equal to " + sixString, "", MessageBoxButtons.OK);
}
private void MySub(bool i_Param1,ref object o_Var)
{
   if (i_Param1)
   {
      o_Var = 5;
   }
   else
   {
      o_Var = "five";
   }
}
public void MySub(bool i_Param1,ref int o_Var)
{
   object TemporaryArg1 = o_Var;
   MySub(i_Param1,ref TemporaryArg1);
   o_Var = Convert.ToInt32(TemporaryArg1);
}
public void MySub(bool i_Param1,ref string o_Var)
{
   object TemporaryArg1 = o_Var;
   MySub(i_Param1,ref TemporaryArg1);
   o_Var = Convert.ToString(TemporaryArg1);
}
In this overloaded translation the calling code is able to pass its local variables directly ByRef; so those variables will receive their intended values. The actual method code does not force any typing or conversion operations on the variant parameter. The addition of the two additional versions of that method make this possible. Note that multiple parameters of a method may be overloaded. In this case the tool will produced overloaded version for every possible combination.

The Overload statement does not require that all calling arguments have one of the types specified in the Types attribute for a given parameter. Consider an alternate version of the VB6 source in which the type of fiveNumber is single.


 Dim fiveNumber As Single
Using the equivalent Overload statement as before


<Compile Project="..\vb6\Project2.vbp" >
   <Refactor>
      <OverLoad identifier="Project2.Form2.MySub.o_Var" Types="Integer,String" />
   </Refactor>
</Compile>
produces this progress level 1 warning message


 Warning#3005: Passing/Changed <Project2.Form2.Form_Load.fiveNumber> with
               type <Single> to <Project2.Form2.MySub.o_Var> with type <Variant>
and this translation of the calling code


string fiveString = "";
float fiveNumber = 0.0F;
MySub(false,ref fiveString);
object argTemp1 = fiveNumber;
MySub(true,ref argTemp1);
in which the passage of the number again is forced to revert to using a temporary.
Table of Contents