Today I’ll be discussing another great feature of the ASNA Visual RPG (AVR) for .NET language. This feature is called method overloading and it provides two great benefits to your coding efforts;
- Simplifies complex coding requirements
- Enhances code performance
In AVR, method overloading simply means that functions in an AVR class can have the same name but with different parameters passed to it. The name of a function, combined with the set of parameters passed to it, form what is called the signature of the method. Here is an example of an overloaded method called GetItem, with three different signatures;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
BegClass ItemDbContext Access(*Public) /// GetItem requiring one parameter /// Returns one item without an order BegFunc GetItem Access(*Public) Type(Item) DclSrParm ItemNumber Type(*Integer4) DclFld Item Type(Item) new() LeaveSr Item EndFunc /// GetItem requiring two parameters /// Returns one item with an order BegFunc GetItem Access(*Public) Type(ItemWithOrder) DclSrParm itemNumber Type(*Integer4) DclSrParm orderNumber Type(*Integer4) DclFld Item Type(ItemWithOrder) new() DclFld order Type(Order) new() order.Number = orderNumber Item.Order = order LeaveSr Item EndFunc /// GetItem requiring no parameters /// Retrieves one item without an order BegFunc GetItem Access(*Public) Type(Item) DclFld Item Type(Item) new() LeaveSr Item EndFunc EndClass |
The AVR.NET compiler will compile all three methods to the intermediate language code as expected. One thing to remember, is that when it comes to overloading a method, the value returned by the method is not considered part of the method signature. As you can see in the second overloaded example of GetItem, it returns a different type from the other two overloaded methods.
Method overloading gives us the ability to provide multiple, unique implementations of the method, while at the same reducing the complexity of the code required to satisfy application requirements. Without the ability to overload the GetItem method, there could only be one implementation of the method. This single implementation would be much more complex, because it would have to perform tests, to determine what kind of argument was passed into each parameter and then branch to the appropriate code, based on the results of each test. All of this testing and branching degrades the runtime performance and efficiency of the method.
Method overloading also provides consumers of the GetItem method with the kind of flexibility and ease-of-use they have come to expect, when interfacing with other .NET classes and methods. The public interface of the ItemDbContext class illustrated above, will expose three methods for retrieving an item object, either with its associated order object or without the order. The consumer of these methods simply has to code the appropriate arguments when invoking the GetItem method and the compiler and common language runtime, will take care of calling the appropriate method. The consumer does not have to be concerned with how these methods are implemented. Their only concern is to satisfy the requirements of the public class interface.
When writing code in Visual Studio that will invoke the GetItem method, the IntelliSense feature of Visual Studio will automatically present each signature of GetItem to the programmer for them to choose from, as illustrated here.
Please feel free to share your thoughts on this post by clicking the leave reply above, or post your comments on Twitter #ASNAVisualRPG.
Below is the complete code for the ItemDbContext class used in the example above. The example application developed for this post, and all of the source code can be downloaded at the following link;
The sample database files, which are included with the example application download, can be imported into a local DataGate database on your PC.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
BegClass ItemDbContext Access(*Public) DclDB AsnaDb DBName("*Public/DG NET Local") // Order Item File by order number and item number DclDiskFile Name(OrderItem) + Prefix(Item_) + Type(*Input) + Org(*Indexed) + ImpOpen(*No) + DB(AsnaDb) + File("ASNA/OrderItem") // Order Item file by Item number DclDiskFile Name(OrderItemL1) + Prefix(Item_) + RnmFmt(RFORMATL1) + Type(*Input) + Org(*Indexed) + ImpOpen(*No) + DB(AsnaDb) + File("ASNA/OrderItemL1") ///Retrieves one item without an order BegFunc GetItem Access(*Public) Type(Item) DclFld Item Type(Item) new() LeaveSr Item EndFunc ///<summary> ///Retrieves one item without an order.</summary> BegFunc GetItem Access(*Public) Type(Item) DclSrParm ItemNumber Type(*Integer4) DclFld Item Type(Item) new() ConnectToDB() Open OrderItemL1 Chain OrderItemL1 Key(ItemNumber) If (OrderItemL1.IsFound) PopulateItemEntity(Item) EndIf DisconnectFromDB() LeaveSr Item EndFunc ///<summary> ///Retrieves one item with an order.</summary> BegFunc GetItem Access(*Public) Type(ItemWithOrder) DclSrParm itemNumber Type(*Integer4) DclSrParm orderNumber Type(*Integer4) DclFld Item Type(ItemWithOrder) new() DclFld order Type(Order) new() ConnectToDb() Open OrderItem Chain OrderItem Key(orderNumber, itemNumber) If(OrderItem.IsFound) PopulateItemEntity(Item) Endif DisconnectFromDB() order.Number = orderNumber Item.Order = order LeaveSr Item EndFunc BegFunc GetList Type(List(*Of Item)) Access(*Public) DclSrParm OrderNumber Type(*Integer4) DclFld itemList Type(List(*Of Item)) new() DclFld order_Item Type(Item) ConnectToDB() Open OrderItem Chain OrderItem Key(OrderNumber) If(OrderItem.IsFound) order_Item = *New Item() order_Item = PopulateItemEntity(order_Item) itemList.Add(order_Item) DoUntil (OrderItem.IsEof) ReadE OrderItem Key(OrderNumber) If (NOT OrderItem.IsEof) order_Item = *New Item() order_Item = PopulateItemEntity(order_Item) itemList.Add(order_Item) Endif EndDo EndIf DisconnectFromDB() LeaveSr itemList EndFunc BegFunc PopulateItemEntity Type(Item) Access(*Private) DclSrParm OrderItem Type(Item) DclFld orderDataContext Type(OrderDbContext) new() DclFld _order Type (Order) new() OrderItem.Description = Item_ITMDESC OrderItem.Number = Item_ORITM OrderItem.Quantity = Item_ITMQTY OrderItem.OrderNumber = Item_ORORD OrderItem.Order = _order LeaveSr OrderItem EndFunc BegSr ConnectToDB Access(*Private) Connect AsnaDb EndSr BegSr DisconnectFromDB Access(*Private) Close *all Disconnect AsnaDb EndSr EndClass |
Method, or subroutine, overloading may look a little foreign to some RPG coders. However, those coders should be reminded that ILE RPG has used method overloading since the mid-90s. Take a look at the ILE RPG docs for how many arguments the %LEN or %SUBST BIFs use. That’s also overloading!
Hi Roger. Thanks for relating the subject of this post back to our RPG roots on the IBMi Server. It is always easier to understand a new concept when you can relate to an old concept you are already familiar with.