Tag Archives: COBOL - Page 4

Base Class Library, Arrays, Queues and Stacks

Continuing the series of blogs about COBOL and the .Net base class library…

The .Net base class library has a wealth classes and an huge of amount of methods/properties.

The .Net base class library has a key handy namespace that contains are the lovely classes, which is System.Collections.

As you can see from the above link, it does have quite a lot, so for this blob entry I will look at:

  • arrays of numbers
  • queues
  • stacks
  • Lets start the first example by using an array of numbers… just to demonstrate its not just strings you can assign to the arrays using “values”.

           01 numbers  binary-long occurs 10
              values 10 20 30 40 50 10 20 30 40 50.

           01 num       binary-long value 0.
           01 average   binary-double value 0.

           procedure division.
              perform varying num through numbers
                add num to average
              end-perform
              divide average by numbers::"Length" giving average
              display "Average is : " average

    Running the above code gives us:

    Average is : +00000000000000000030

    The next class that is helpful, is the Queue class, this allows us to “Enqueue” and “Dequeue” item using the same methods, the queue is again displayed using the “perform through” syntax.

          $set ilusing"System"
          $set ilusing"System.Collections"

           01 alphabetQueue     type "Queue".
           01 item              object reference.

           set alphabetQueue to new type "Queue"()
           invoke alphabetQueue::"Enqueue"("A item")
           invoke alphabetQueue::"Enqueue"("B item")
           invoke alphabetQueue::"Enqueue"("C item")

           display "The initial queue is: "
           perform varying item through alphabetQueue
             display " " item
           end-perform

           display "".
           display "De-Queue an item: " alphabetQueue::"Dequeue"()

           display "".
           display "Afterwards is: "
           perform varying item through alphabetQueue
             display " " item
           end-perform

    Running the above queue example gives:

    The initial queue is:
     A item
     B item
     C item

    De-Queue an item: A item

    Afterwards is:
     B item
     C item

    Next, lets look at the ‘Stack’ class, this is very similar, expect it uses the “Push”, “Pop” methods and we iterate through the Stack using the ‘perform through’ syntax.

          $set ilusing"System"
          $set ilusing"System.Collections"

           01 alphabetStack     type "Stack".
           01 item              object reference.

           set alphabetStack to new type "Stack"()
           invoke alphabetStack::"Push"("A item")
           invoke alphabetStack::"Push"("B item")
           invoke alphabetStack::"Push"("C item")

           display "The initial stack is: "
           perform varying item through alphabetStack
             display " " item
           end-perform

           display "".
           display "Pop item: " alphabetStack::"Pop"()

           display "".
           display "Afterwards is: "
           perform varying item through alphabetStack
             display " " item
           end-perform

    Running the above stack example gives:

    The initial stack is:
     C item
     B item
     A item

    De-Stack an item: C item

    Afterwards is:
     B item
     A item

    As you can see using the base class library collection classes with COBOL is just as easy as using C#… so if you are already using COBOL… continue and try out the .Net base class library.. it really is very easy to use and it will make you more productive.. so please explore and enjoy .Net and its Base Class library.

    TechEd 2009 – Keynote with Jazon and Mark

    My boss (Mark Conway) the other day was lucky enough to demonstrate some of the wonders of next release at TechEd 2009 in the keynote with Jazon Zander’s entitled: “Visual Studio 2010: New Challenges, New Solutions”

    The demo shows off some of the nice features of Visual Studio 2010 and how we looking to use it for COBOL. I think it looks great! :-)

    Tip: Skip to about 34 mins into it for Mark

    Click here for TechEd Online – for the actual video

    And finally here is Jazon Zander’s Blog.

    Too Iterate or not…

    Over the next couple of weeks, I will explore some of the reasons why I think managed environments are good for COBOL.

    So.. lets the show on the road…

    Setting up arrays/occurs items in COBOL and manipulating them can be painful. Lets look at some traditional code for playing around with a “months” table.

           01 month-val.
               05  FILLER                    PIC X(10)  value "January".
               05  FILLER                    PIC X(10)  value "February".
               05  FILLER                    PIC X(10)  value "March".
               05  FILLER                    PIC X(10)  value "April".
               05  FILLER                    PIC X(10)  value "May".
               05  FILLER                    PIC X(10)  value "June".
               05  FILLER                    PIC X(10)  value "July".
               05  FILLER                    PIC X(10)  value "August".
               05  FILLER                    PIC X(10)  value "September".
               05  FILLER                    PIC X(10)  value "October".
               05  FILLER                    PIC X(10)  value "November".
               05  FILLER                    PIC X(10)  value "December".

           01 month-tab redefines month-val.
               05  months occurs 12 times.
                   10  month-NAME            PIC X(10).

           01 month                          PIC 99.

           01 secondQuarterMonths            pic x(70).
     
           display "The months are:"
           perform varying month from 1 by 1 until month equals 12
             display " " months(month)    
           end-perform

           display " "
           display "The second quarter months are: "

           string months(4) delimited by space
                  "/" delimited by size
                  months(5) delimited by space
                  "/" delimited by size
                  months(6) delimited by space
              into secondQuarterMonths
              on overflow
                 display "FATAL Error - secondQuarterMonths is too small"
                 stop run
           end-string

           display " " secondQuarterMonths

    Now, imagine we can use one or two of the .Net’s base class libraries combined with some nifty natural extensions to COBOL to do some of the heavy lifting.

    Defining the month item as a native .Net type ie: a string combined with using the base class libraries Split methods allows us to setup a array quickly.

            01 commaDelimited       string value
             "January,February,March,April,May,June,July,August," &
             "September,October,November,December".

            01 months              string occurs any.
            01 month               string.

            01 secondQuarterMonths  string.

            set months to commaDelimited::"Split"(',')

            display "The months are: "
            perform varying month through months
              display " " month
            end-perform

            display " "
            display "The second quarter months are: "

            set secondQuarterMonths to type "System.String"::"Join"('/', months, 3, 3)

            display " " secondQuarterMonths

    The .Net version, besides being smaller feels much easier to read, especially if you have any exposure to the .Net base class library from other languages such as C# or VB.Net.

    Of course in a real world example, we don’t need to use the split method to setup an array, we could just use the “values” clause… for example:

          01 months  string occurs 12 values
             "January" "February" "March" "April" "May" "June"
             "July" "August" "September" "October" "November" "December".

           01 month string.

               perform varying month through months
                   display month
               end-perform

    If however you don’t want to hardcode the months, you can always use: CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName() in the System.Globalization namespace. :-)

    So… lets just do it…

           01 Months string occurs any.
           01 Month string.

           set Months to type "System.Globalization.DateTimeFormatInfo"::
              "CurrentInfo"::"MonthNames"
               
           perform varying Month through Months
              display Month
           end-perform

    Now, I hope you feel like I do that COBOL and .Net are indeed perfect partners to each other.


    The above COBOL .Net code will execute on Micro Focus Net Express and I suspect it will also work on Fujitsu’s netCobol too.

    NUnit and COBOL.Net

    A while back, I spent a afternoon converting some C# NUnit documentation into COBOL .Net, so I thought I would share the document with the world, with the hope that it will help any one interested in using NUnit and COBOL.

    Enjoy!


    Let’s start with a simple example. Suppose we are writing a bank application and we have a basic domain class – Account. Account supports operations to deposit, withdraw, and transfer funds. The Account class may look like this:

           class-id. Account as "Account".
           environment division.
           configuration section.
           repository.
           object.
           data division.
           working-storage section.
           01 balance comp-2 value 0 property as "Balance".
           
           method-id. "Deposit".
           local-storage section.
           linkage section.
           01 lnk-amount comp-2.
           procedure division using by value lnk-amount.
               add lnk-amount to balance
               exit method.          
           end method "Deposit".
         
           method-id. "Withdraw".
           local-storage section.
           linkage section.
           01 lnk-amount comp-2.
           procedure division using by value lnk-amount.
               subtract lnk-amount from balance
               exit method.          
           end method "Withdraw".
           
           method-id. "TransferFunds".
           local-storage section.
           linkage section.
           01 lnk-Account   object reference Account.
           01 lnk-amount    comp-2.
           procedure division using by value lnk-Account,
                                    by value lnk-amount.
               exit method.          
           end method "TransferFunds".      
           end object.
           end class Account.

    Now let’s write a test for this class – AccountTest. The first method we will test is TransferFunds.

          $set preservecase
           class-id. AccountTest as "AccountTest".

           environment division.
           configuration section.
           repository.
            class sys-single    as "System.Single"
            class cls-TestFixture as "NUnit.Framework.TestFixtureAttribute"
            class cls-Test        as "NUnit.Framework.TestAttribute"
            class Assert          as "NUnit.Framework.Assert"
           
            class cls-Account     as "Account"
            .
           
           class-attributes.
               custom-attribute is cls-TestFixture.

           static.
           data division.
           working-storage section.
           end static.
         
           object.    
           method-id. "TransferFunds" custom-attribute is cls-Test.
           local-storage section.
           01 src   object reference cls-Account.
           01 dest  object reference cls-Account.
           procedure division.
            set src to cls-Account::"New"
            invoke src::"Deposit"(200)
           
            set dest to cls-Account::"New"
            invoke dest::"Deposit"(150)
           
            invoke src::"TransferFunds"(dest, 100);
           
            invoke Assert::"AreEqual"(250 as sys-single,dest::"Balance")
            invoke Assert::"AreEqual"(100 as sys-single,src::"Balance")
            exit method.    
           end method "TransferFunds".
           end object.
           end program AccountTest.

    The first thing to notice about this class is that it has a TestFixture attribute associated with it – this is the way to indicate that the class contains test code (this attribute can be inherited). The class has to be public and there are no restrictions on its superclass. The class also has to have a default constructor.

    The only method in the class – TransferFunds, has a Test attribute associated with it – this is an indication that it is a test method. Test methods have to return void and take no parameters. In our test method we do the usual initialization of the required test objects, execute the tested business method and check the state of the business objects. The Assert class defines a collection of methods used to check the post-conditions and in our example we use the AreEqual method to make sure that after the transfer both accounts have the correct balances (there are several overloadings of this method, the version that was used in this example has the following parameters : the first parameter is an expected value and the second parameter is the actual value).

    Compile and run this example. Assume that you have compiled your test code into a Example1.dll. Start the NUnit Gui (the installer will have created a shortcut on your desktop and in the “Program Files” folder), after the GUI starts, select the File->Open menu item, navigate to the location of your bank.dll and select it in the “Open” dialog box. When the bank.dll is loaded you will see a test tree structure in the left panel and a collection of status panels on the right. Click the Run button, the status bar and the TransferFunds node in the test tree turn red – our test has failed. The “Errors and Failures” panel displayed the following message – “TransferFunds : expected <250> but was <150>” and the stack trace panel right below it reported where in the test code the failure has occurred “at AccountTest.TransferFunds() in xxxx\Example1\Example1\AccountTest.cbl:line 42”

    That is expected behavior; the test has failed because we have not implemented the TransferFunds method yet. Now let’s get it to work. Don’t close the GUI and go back to your IDE and fix the code, make your TransferFunds method look like this:

           method-id. "TransferFunds".
           local-storage section.
           linkage section.
           01 lnk-Account   object reference Account.
           01 lnk-amount    comp-2.
           procedure division using by value lnk-Account,
                                    by value lnk-amount.
               invoke lnk-Account::"Deposit"(lnk-amount)
               invoke self::"Withdraw"(lnk-amount)
               exit method.          
           end method "TransferFunds".

    Now recompile your code and click the run button in GUI again – the status bar and the test tree turn green. (Note how the GUI has reloaded the assembly automatically for you; we will keep the GUI open all the time and continue working with our code in IDE and write more tests).

    Let’s add some error checking to our Account code. We are adding the minimum balance requirement for the account to make sure that banks continue to make their money by charging your minimal overdraft protection fee. Let’s add the minimum balance property to our Account class:

           01 minimumBalance    comp-2 value 10
                        property as "MinimumBalance".

    We will use an exception to indicate an overdraft:

           class-id. InsufficientFundsException  
                     as "InsufficientFundsException"
                     inherits cls-exception.

           repository.
             class cls-exception as "System.ApplicationException".
           object.
           object-storage section.      
           end object.
           
           end class InsufficientFundsException.

    Add two new classes reference to the repository:

         class ExpectedException
               as "NUnit.Framework.ExpectedExceptionAttribute"
         class InsufficientFundsException
               as "InsufficientFundsException"

    Add a new test method to our AccountTest class:

         method-id. "TransferWithInsufficientFunds"
             custom-attribute is cls-Test
             custom-attribute is ExpectedException(
                   type of InsufficientFundsException)
           .
           local-storage section.
           01 src   object reference cls-Account.
           01 dest  object reference cls-Account.
           procedure division.
            set src to cls-Account::"New"
            invoke src::"Deposit"(200)
           
            set dest to cls-Account::"New"
            invoke dest::"Deposit"(150)
           
            invoke src::"TransferFunds"(dest, 300);
            exit method.    
           end method "TransferWithInsufficientFunds".

    This test method in addition to Test attribute has an ExpectedException attribute associated with it – this is the way to indicate that the test code is expecting an exception of a certain type; if such an exception is not thrown during the execution – the test will fail.

    Compile your code and go back to the GUI. As you compiled your test code, the GUI has grayed out and collapsed the test tree as if the tests were not run yet (GUI watches for the changes made to the test assemblies and updates itself when the structure of the test tree has changed – e.g. new test is added). Click the “Run” button – we have a red status bar again. We got the following Failure : “TransferWithInsufficentFunds : InsufficientFundsException was expected”. Let’s fix our Account code again, modify the TransferFunds method this way:

           method-id. "TransferFunds".
           local-storage section.
           linkage section.
           01 lnk-Account   object reference Account.
           01 lnk-amount    comp-2.
           procedure division using by value lnk-Account,
                                    by value lnk-amount.
                                   
               invoke lnk-Account::"Deposit"(lnk-amount)
               if balance - lnk-amount < minimumBalance
                 raise InsufficientFundsException::"New"()
               end-if
                 
               invoke self::"Withdraw"(lnk-amount)
               exit method.          
           end method "TransferFunds".

    Compile and run the tests – green bar. Success! But wait, looking at the code we’ve just written we can see that the bank may be loosing money on every unsuccessful funds Transfer operation. Let’s write a test to confirm our suspicions. Add this test method:

           method-id. "TransferWithInsufficientFundsAtomicity"
                   custom-attribute is cls-Test
           .
           local-storage section.
           01 src   object reference cls-Account.
           01 dest  object reference cls-Account.
           01 obj-InsufficientFundsException
              object reference InsufficientFundsException.
           procedure division.
            set src to cls-Account::"New"
            invoke src::"Deposit"(200)
           
            set dest to cls-Account::"New"
            invoke dest::"Deposit"(150)
           
            try
              invoke src::"TransferFunds"(dest, 300)
            catch obj-InsufficientFundsException
              continue
            end-try
           
            invoke Assert::"AreEqual"(200 as sys-single,src::"Balance")
            invoke Assert::"AreEqual"(150 as sys-single,dest::"Balance")

            exit method.    
           end method "TransferWithInsufficientFundsAtomicity".

    We are testing the transactional property of our business method – all operations are successful or none. Compile and run – red bar. OK, we’ve made $300.00 out of a thin air (1999.com déjà vu?) – the source account has the correct balance of 150.00 but the destination account shows : $450.00. How do we fix this? Can we just move the minimum balance check call in front of the updates:

           method-id. "TransferFunds".
           local-storage section.
           linkage section.
           01 lnk-Account   object reference Account.
           01 lnk-amount    comp-2.
           procedure division using by value lnk-Account,
                                    by value lnk-amount.
                                   
               if balance - lnk-amount < minimumBalance
                 raise InsufficientFundsException::"New"()
               end-if
               
               invoke lnk-Account::"Deposit"(lnk-amount)
                 
               invoke self::"Withdraw"(lnk-amount)
               exit method.          
           end method "TransferFunds".

    What if the Withdraw() method throws another exception? Should we execute a compensating transaction in the catch block or rely on our transaction manager to restore the state of the objects? We need to answer those questions at some point, but not now; but what do we do with the failing test in the meantime – remove it? A better way is to temporarily ignore it, add the following attribute to your test method

      method-id. "TransferWithInsufficientFundsAtomicity"
                   custom-attribute is cls-Test
                   custom-attribute is
      IgnoreTest("Need to decide how to implement transaction management in the application")

    Compile and run – yellow bar. Click on “Tests Not Run” tab and you will see AccountTest.TransferWithInsufficientFundsAtomicity() in the list along with the Reason this test is ignored.

    Looking at our test code we can see that some refactoring is in order. All test methods share a common set of test objects. Let’s extract this initialization code into a setup method and reuse it in all of our tests. The refactored version of our test class looks like this:

          $set preservecase sourceformat"free"
           class-id. AccountTest as "AccountTest".

           environment division.
           configuration section.
           repository.
            class sys-single    as "System.Single"
            class NUnit-TestFixture             as
                  "NUnit.Framework.TestFixtureAttribute"
            class NUnit-Test                    as
                 "NUnit.Framework.TestAttribute"
            class NUnit-Setup                   as
                 "NUnit.Framework.SetUpAttribute"
            class NUnit-Assert                  as
                 "NUnit.Framework.Assert"
            class NUnit-IgnoreTest              as
                 "NUnit.Framework.IgnoreAttribute"
            class NUnit-ExpectedException             as
                 "NUnit.Framework.ExpectedExceptionAttribute"
           
            class cls-Account                   as
                  "Account"
            class InsufficientFundsException                as
                  "InsufficientFundsException"
            .

           class-attributes.
               custom-attribute is NUnit-TestFixture.
             
           object.    
           working-storage section.
           01 src   object reference cls-Account.
           01 dest  object reference cls-Account.

           method-id. "Init"
            custom-attribute is NUnit-Setup.
           procedure division.
               set src to cls-Account::"New"
               set dest to cls-Account::"New"
               
               invoke src::"Deposit"(200)
               invoke dest::"Deposit"(150)
               exit method.    
           end method "Init".

           method-id. "TransferFunds"
            custom-attribute is NUnit-Test.
           procedure division.
            invoke src::"TransferFunds"(dest, 100);
            invoke NUnit-Assert::"AreEqual"(250,dest::"Balance")
            invoke NUnit-Assert::"AreEqual"(100,src::"Balance")
            exit method.    
           end method "TransferFunds".
           
           method-id. "TransferWithInsufficientFunds"
            custom-attribute is NUnit-Test
            custom-attribute is
                  NUnit-ExpectedException(
                   type of InsufficientFundsException).
           procedure division.
            invoke src::"TransferFunds"(dest, 300)
            exit method.    
           end method "TransferWithInsufficientFunds".
           
           method-id. "TransferWithInsufficientFundsAtomicity"
            custom-attribute is NUnit-Test
            custom-attribute is NUnit-IgnoreTest(
              "Need to decide how to implement transaction management in the application").
           local-storage section.
           01 obj-InsufficientFundsException
              object reference InsufficientFundsException.
           procedure division.
            try
              invoke src::"TransferFunds"(dest, 300)
            catch obj-InsufficientFundsException
              continue
            end-try
           
            invoke NUnit-Assert::"AreEqual"(
                  200 as sys-single,src::"Balance")
            invoke NUnit-Assert::"AreEqual"(
                  150 as sys-single,dest::"Balance")
            exit method.    
           end method "TransferWithInsufficientFundsAtomicity".  
           
           end object.
           end program AccountTest.

    Note that Init method has the common initialization code, it has void return type, no parameters, and it is marked with SetUp attribute. Compile and run – same yellow bar!

    Visual Debugger – Animator

    This is a very old advertisement of our (Micro Focus) first COBOL debugger called animator in all its glory debugging the classic sample of the day pi.cbl, which calculates the value of PI.

    So why is so good?

    To put it in some kind of context, most debuggers at the time were command line based, much like gdb, dbx but far less sophisticated.   So having a debugger that actually shows the execution of flow of your, query variables, monitor variables was truly application was amazing.

    I have no idea, who put this on YouTube but it really does bring back some old memories.  So thank you!